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

标签 arrays scala scala-collections invariance

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/

相关文章:

Javascript:如何循环遍历对象数组以发送数组属性的请求?

scala - 编译器说我没有为 Set 指定类型(类型不匹配)

scala - <not computed> 关于 Scala 中的集合输出

scala - 在到达第一个None时如何停止构建Option [Collection]?

sql - 根据 jsonb 数组中的嵌套键查找行

javascript - 如何使用 id 上匹配的另一个 2D 数组更新 2D 数组

scala - 如何编写一个简单地进行行收集的 Spark UDAF?

scala - Scala 的 “if … else” 可以作为库函数实现吗?

scala - 对归并排序的实现感到困惑

ruby - 根据值将数组拆分为子数组