根据List[+T]
,我知道狗的列表也是与直觉完全一致的动物列表。根据def :: [B >: A](elem: B): List[B]
,我知道我可以将一只动物(B
,不太具体(添加到狗的列表(A
,更具体(中,并将返回动物列表。这也符合直觉。所以基本上List
是好的。
根据Array[T]
,我了解到狗的阵列不是动物的阵列(不能代替a(,这相当违反直觉。狗的阵列实际上也是动物的阵列,但显然Scala不同意。
我希望有人能直观地解释为什么Array
是不变的,最好是用狗(或猫(的术语。
为什么数组是不变的,而列表是协变的?但我正在寻找一个更直观的解释,不(严重(涉及类型系统。
与Scala';s不可变集的类型不是协变的?
Array
是可变的集合。请记住,关于方差有一条非常简单的经验法则如果它产生某种东西,它可以是协变
如果它消耗了一些东西,它可以是反变量
这就是为什么
Functions
在输入上是反变量而在输出上是协变。
因为Arrays
是可变的,所以它们实际上既是某种东西的生产者又是消费者,所以它们必须是不变的。
让我用一个简单的例子来说明为什么它必须是这样的。
// Assume this compiles, it doesn't.
final class CovariantArray[+A] (arr: Array[A]) {
def length: Int = arr.length
def apply(i: Int): A = arr(i)
def update(i: Int, a: A): Unit = {
arr(i) = a
}
}
sealed trait Pet
final case class Dog(name: String) extends Pet
final case class Cat(name: String) extends Pet
val myDogs: CovariantArray[Dog] = CovariantArray(Dog("Luna"), Dog("Lucas"))
val myPets: CovariantArray[Pet] = myDogs // Valid due covariance.
val myCat: Cat = Cat("Milton")
myPets(1) = myCat // Valid because Liskov.
val myDog: Dog = myDogs(1) // Runtime error Cat is not Dog.
您可以使用普通的Arrays
在Java中重现此错误,Scala将不允许您进行编译。