这是本教程的一些代码:
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 = h和def tail: ListNode[T] = t)显然是协变的?
什么我问的是,为什么T在prepend不协变.这当然不包括在为什么函数[-A1,...,+ B]没有关于允许任何超类型作为参数?,这似乎是其他人指导我阅读的内容.
方法的输入参数不是协变位置而是逆变位置.只有返回类型的方法处于协变位置.
如果你对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.
| 归档时间: |
|
| 查看次数: |
1235 次 |
| 最近记录: |