直观地解释为什么"List"是协变的,而"Array"是不变的



根据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.

您可以使用普通的ArraysJava中重现此错误,Scala将不允许您进行编译。

相关内容

  • 没有找到相关文章

最新更新