从 List[+T]
我了解到狗的列表也是与直觉完全一致的动物列表。从 def :: [B >: A](elem: B): List[B]
我知道我可以将动物( B
,不太具体)添加到狗列表( A
,更具体)中,并将返回动物列表。这也符合直觉。所以基本上 List
是好的。
从 Array[T]
我了解到,一组狗不是(不能用来代替 a)一组相当违反直觉的动物。一组狗确实也是一组动物,但显然 Scala 不同意。
我希望有人能直观地解释为什么 Array
是不变的,最好是用狗(或猫)来解释。
有 Why are Arrays invariant, but Lists covariant? 但我正在寻找一个更直观的解释,它不(大量)涉及类型系统。
关于 Why is Scala's immutable Set not covariant in its type?
最佳答案
原因很简单。是因为 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 根本不会让您编译。
关于arrays - 直观地解释为什么 `List` 是协变的,而 `Array` 是不变的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65183904/