为什么cons
's 的参数类型错误?
trait List[+A] {
def cons(hd: A): List[A]
}
编译器给你错误:
covariant type A occurs in contravariant position in type A of value hd
因为方法参数算作逆变位置,但是A
是协变的。
让我们假设这个方法声明可以编译。然后我们可以这样做:
class ListImpl[A] extends List[A] {
override def cons(hd: A): List[A] = ???
}
val strings: List[String] = new ListImpl[String]
val values: List[Any] = strings // OK, since List[String] <: List[Any] (in List[A], A is covariant)
values.cons(13) // OK(??), since values's static type is List[Any], so argument of cons should be Any, and 13 conforms to type Any
上面最后一行真的没问题吗?我们正在cons
呼吁values
。values
与 相同strings
,并且strings
是类型的对象ListImpl[String]
。所以cons
最后一行中的调用期待String
参数,但我们正在传递Int
,因为values
的静态类型是List[Any]
并且Int
符合Any
。这里肯定有问题 - 应该归咎于哪条线?答案是:cons
方法声明。要解决此问题,我们必须A
从逆变位置(在cons
声明中)删除协变类型参数。或者,我们可以使A
非协变。
另请参阅以下问题:#1、#2。
...没有cons
遇到问题?
trait List[+A] {
def cons[B >: A](v: B): List[B]
}
val animal_list: List[Animal] = List(tiger, dog) // We are assuming that List.apply and concrete implementation of List is somewhere defined.
不,animal_list.cons(tiger)
调用是类型正确的。
我假设 that是andAnimal
的常见超类型,并且and分别是and的实例。Dog
Tiger
dog
tiger
Dog
Tiger
在animal_list.cons(tiger)
调用中,参数A
和B
类型参数都实例化为Animal
,因此cons
方法采用以下形式:
def cons[Animal >: Animal](v: Animal): List[Animal]
Animal >: Animal
约束得到满足,因为:
超类型和子类型关系是自反的,这意味着类型既是超类型又是其自身的子类型。[来源]
cons
to的参数Tiger
符合 type Animal
,因此方法调用是类型正确的。
请注意,如果您强制B
实例化为Tiger
, like animal_list.cons[Tiger](tiger)
,那么此调用将不是类型正确的,并且您将收到编译器错误。
在此处查看类似示例。