4

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

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

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

为什么数组是不变的,而列表是协变的?但我正在寻找一个不(大量)涉及类型系统的更直观的解释。

为什么 Scala 的不可变 Set 在其类型上不协变有关?

4

1 回答 1

16

原因很简单。是因为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.

您可以使用 normal在Java中重现此错误ArraysScala根本不会让您编译。

于 2020-12-07T15:09:39.073 回答