[英]Intuitively explain why `List` is covariant but `Array` is invariant?
From List[+T]
I understand a list of dogs is also a list of animals which aligns perfectly with the intuition.从
List[+T]
我了解到狗列表也是与直觉完全一致的动物列表。 From def:: [B >: A](elem: B): List[B]
I understand I can add an animal ( B
, less specific) to a list of dogs ( A
, more specific) and will get back a list of animals.来自
def:: [B >: A](elem: B): List[B]
我知道我可以将动物( B
,不太具体)添加到狗列表( A
,更具体)并会得到一个列表的动物。 This aligns with the intuition as well.这也符合直觉。 So basically
List
is good.所以基本上
List
是好的。
From Array[T]
I understand an array of dogs is not (could not be used in place of a) an array of animals which is rather counterintuitive.从
Array[T]
我了解到一组狗不是(不能用来代替 a)一组相当违反直觉的动物。 An array of dogs is indeed an array of animals as well but obviously Scala disagrees.一组狗确实也是一组动物,但显然 Scala 不同意。
I was hoping someone intuitively explain why Array
in invariant, preferably in terms of dogs (or cats).我希望有人能直观地解释为什么
Array
是不变的,最好是用狗(或猫)来解释。
There is Why are Arrays invariant, but Lists covariant?还有为什么 Arrays 是不变的,但 Lists 是协变的? but I'm looking for a more intuitive explanation that doesn't (heavily) involve the type system.
但我正在寻找一个不(大量)涉及类型系统的更直观的解释。
Related to Why is Scala's immutable Set not covariant in its type?与为什么 Scala 的不可变 Set 在其类型上不协变有关?
The reason is pretty simple.原因很简单。 Is because
Array
is a mutable collection.是因为
Array
是一个可变集合。 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.这就是为什么
Functions
在输入上是逆变的,而在 output 上是协变的。
Because Arrays
are mutable they are in fact both producers and consumers of something, so they have to be invariant .因为
Arrays
是可变的,它们实际上既是生产者又是消费者,所以它们必须是不变的。
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.
You can reproduce this error in Java using normal Arrays
, Scala will simply not let you compile.您可以使用普通的
Arrays
在Java中重现此错误, Scala根本不会让您编译。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.