【发布时间】:2015-05-21 06:13:16
【问题描述】:
这里有一些来自this教程的代码:
case class ListNode[+T](h: T, t: ListNode[T]) {
def head: T = h
def tail: ListNode[T] = t
def prepend(elem: T): ListNode[T] =
ListNode(elem, this)
}
教程说:
不幸的是,这个程序无法编译,因为协方差 仅当类型变量仅用于 协变位置。由于类型变量 T 作为参数类型出现 的方法前置,这条规则被打破了。
T 如何在 predend 中不处于协变位置,而其他 T 引用(def head: T = h 和 def tail: ListNode[T] = t)显然是协变的?
我要问的是为什么prepend 中的T 不是协变的。这在Why is Function[-A1,...,+B] not about allowing any supertypes as parameters? 中肯定没有涉及,这似乎是其他人指导我阅读的内容。
【问题讨论】:
-
如所写。其他两个方法中
T处于逆变位置,返回类型only,而prepend也在参数(elem: T)中,所以只能保持不变。 -
考虑以下示例:
trait Fruit; class Apple extends Fruit; class Pear extends Fruit。假设ListNode是协变的,所以ListNode[Apple]也是ListNode[Fruit]:val node: ListNode[Fruit] = ListNode[Apple](new Apple(), null)。现在,如果你prepend和另一个Fruit、node.prepend(new Pear()),你显然不会得到一个(类型安全的)ListNode[Apple]。
标签: scala covariance contravariance