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

Ash*_*ary 3 arrays scala scala-collections invariance

List[+T]我了解,狗的列表也是与直觉完全一致的动物列表。据def :: [B >: A](elem: B): List[B]我所知,我可以将动物(B,不太具体)添加到狗(A,更具体)列表中,并会取回动物列表。这也符合直觉。所以基本上List是好的。

Array[T]我了解,一组狗不是(不能用来代替 a)一组相当违反直觉的动物。一组狗确实也是一组动物,但显然 Scala 不同意。

我希望有人能直观地解释为什么Array是不变的,最好是用狗(或猫)来解释。

还有为什么阵列不变,但名单协变?但我正在寻找一个更直观的解释,它不(大量)涉及类型系统。

为什么 Scala 的不可变集合的类型不协变有关?

Lui*_*rez 15

The reason is pretty simple. Is because Array is a mutable collection. Remember there is a very easy rule of thumb about variance.
If it produces something it can be covariant.
If it consumes something it can be contravariant.
That is why Functions are contravariant on input and covariant on output.

Because Arrays are mutable they are in fact both producers and consumers of something, so they have to be invariant.

Let me show why it has to be like that with a simple example.

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

You can reproduce this error in Java using normal Arrays, Scala will simply not let you compile.