为什么输入参数在方法中是逆变的?

Roy*_*man 4

这是教程的一些代码:

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)
}
Run Code Online (Sandbox Code Playgroud)

教程说:

不幸的是,这个程序不能编译,因为只有在变量位置使用类型变量时才能进行协方差注释.由于类型变量T作为方法前置的参数类型出现,因此该规则被破坏.

如何T处于协变位置predend,其他T参考(def head: T = hdef tail: ListNode[T] = t)显然是协变的?

什么我问的是,为什么Tprepend不协变.这当然不包括在为什么函数[-A1,...,+ B]没有关于允许任何超类型作为参数?,这似乎是其他人指导我阅读的内容.

nic*_*_zs 5

方法的输入参数不是协变位置而是逆变位置.只有返回类型的方法处于协变位置.

如果你对ListNode类的定义好的,那么我可以写这样的代码:

val list1: ListNode[String] = ListNode("abc", null)
val list2: ListNode[Any] = list1  // list2 and list1 are the same thing
val list3: ListNode[Int] = list2.prepend(1) // def prepend(elem: T): ListNode[T]
val x: Int = list3.tail.head // ERROR, x in fact is "abc"
Run Code Online (Sandbox Code Playgroud)

看看,如果参数协变位置,那么容器总是可以保存另一种类型的值,它具有与其真实类型相同的祖先,这绝对是错误的!

因此,参考scala.collection.immutable.List.::的源代码,您的类应该定义为:

case class ListNode[+T](h: T, t: ListNode[T]) {
  def head: T = h
  def tail: ListNode[T] = t
  def prepend[A >: T](elem: A): ListNode[A] = ListNode(elem, this)
}
Run Code Online (Sandbox Code Playgroud)

参数类型A是一个新的类型参数,其下限为T.