逆变和值
'val' 和 'case' 如何以及为何影响类型系统? (尤其是方差)
Welcome to Scala version 2.8.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_22).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class E[-A]
defined class E
scala> class F[-A](val f: E[A] => Unit)
<console>:6: error: contravariant type A occurs in covariant position in type => (E[A]) => Unit of value f
class F[-A](val f: E[A] => Unit)
^
scala> case class C[-A](f: E[A] => Unit)
<console>:6: error: contravariant type A occurs in covariant position in type => (E[A]) => Unit of value f
case class C[-A](f: E[A] => Unit)
scala> class F[-A](f: E[A] => Unit)
defined class F
How and why does 'val' and 'case' affect the type system? (Especially the variance)
Welcome to Scala version 2.8.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_22).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class E[-A]
defined class E
scala> class F[-A](val f: E[A] => Unit)
<console>:6: error: contravariant type A occurs in covariant position in type => (E[A]) => Unit of value f
class F[-A](val f: E[A] => Unit)
^
scala> case class C[-A](f: E[A] => Unit)
<console>:6: error: contravariant type A occurs in covariant position in type => (E[A]) => Unit of value f
case class C[-A](f: E[A] => Unit)
scala> class F[-A](f: E[A] => Unit)
defined class F
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
考虑一下:
如果
f
在F
外部不可见,则不会发生此问题。Consider this:
If
f
is not visible outsideF
, this problem can't happen.你问方差是什么?如果您知道方差是什么,这是不言自明的。没有“val”或“case”的示例没有涉及 A 的外部可见成员,因此它不会引起方差错误。
Are you asking what variance is? If you know what variance is, this is self-explanatory. The example without "val" or "case" has no externally visible members involving A, so it can't induce a variance error.
“val”表示该字段外部可见。考虑一下:
基本上,我们设法不安全地转换 f 而不明确执行它。这只适用于 f 可见,即如果您将其定义为 val 或使用 case 类。
The 'val' means that the field is externally visible. Consider:
Basically, we managed to unsafely cast f without acting for it explicitly. This only works is f is visible, i.e. if you define it as a val or use a case class.
这是一个逆变的“输出通道”,仅打印到控制台:
这里它正在运行:
还没有什么有趣的。关于逆变的一个很酷的事情是,您现在可以安全地将此输出通道分配给接受 T 的任何子类的通道:
现在,想象一下,如果我们向输出通道添加历史跟踪 - 以返回已发送出去的内容的列表远的。
如果上面的代码确实编译通过,基于 String 的输出通道的用户将会遇到一个问题:
由于逆变允许这种类型的“缩小”(即这里从 Any 到 String),所以类型系统无法公开类型 T 的值,例如我做的这个“历史”字段,或者你的“f”字段。
其他著名的“逆向投资者”是函数和比较器:
Here's a contravariant "output channel" that just prints to the console:
Here it is in action:
Nothing interesting yet. The cool thing about contravariance is you can now safely assign this output channel to one that accepts any subclass of T:
Now, imagine if we added a history tracking to the output channel - to give back a List of things that have been sent out thus far.
If the above did compile, the user of the String-based output channel would have a problem:
Since contravariance allows this "narrowing" of types (ie from Any to String here), the type system cannot expose values of type T, such as this "history" field I did, or the "f" field you had.
Other famous "contrarians" are Function and Comparators: