简体   繁体   English

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

[英]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.您可以使用普通的ArraysJava中重现此错误, Scala根本不会让您编译。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM