当前位置: 首页 > 知识库问答 >
问题:

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

白昊乾
2023-03-14

从《狗的名单》中我了解到,《狗的名单》也是一份与直觉完美吻合的动物名单。从定义::[B

我从数组中了解到,狗的数组不是(不能代替a)动物的数组,这是相当违反直觉的。一组狗确实也是一组动物,但显然斯卡拉不同意。

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

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

与Scala的不可变集的类型为何不协变有关?

共有1个答案

陆臻
2023-03-14

原因很简单。是因为Array是一个可变集合。请记住,关于方差有一个非常简单的经验法则。
如果它产生一些东西,它可以是协变的。
如果它消耗一些东西,它可以是逆变的。
这就是为什么Functions在输入上是逆变的,在输出上是协变的。

因为数组是可变的,所以它们实际上既是某事物的生产者又是消费者,所以它们必须是不变的。

让我用一个简单的例子来说明为什么会这样。

scala prettyprint-override">// 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.

您可以使用普通数组在Java中重现此错误,Scala将不允许您编译。

 类似资料:
  • 从Joshua Bloch的Effective Java中, > 数组与泛型类型有两个重要的区别。第一个数组是协变的。泛型是不变的。 协变简单地说,如果X是Y的子型,那么X[]也将是Y[]的子型。数组是协变的,因为字符串是对象的子类型,所以 不变简单地说,不管X是不是Y的子类型, 我的问题是为什么决定在Java中使数组是协变的?还有其他的SO帖子,比如为什么数组是不变的,但是列表是协变的?,但它们

  • 问题内容: 摘自Joshua Bloch的Effective Java, 数组在两个重要方面不同于通用类型。第一数组是协变的。泛型是不变的。 协变量仅表示如果X是Y的子类型,则X []也将是Y []的子类型。数组是协变的,因为字符串是Object的子类型,所以 不变式仅表示X是否为Y的子类型, 问题答案: Java和C#的早期版本不包含泛型(又称参数多态性)。 在这种情况下,使数组不变会排除有用的

  • 问题内容: 这一直使我感到困惑。看起来这样会更好: 比这个: 是否有特定原因? 问题答案: 这是因为任何可迭代对象都可以连接(例如,列表,元组,字典,集合),但是其内容和“连接器” 必须是 字符串。 例如: 使用字符串以外的其他东西会引发以下错误:

  • rank ▲ ✰ vote url 37 511 93 416 url 为什么是string.join(list)而不是list.join(string)? 我一直被这个问题困扰.如果这样写更好: my_list = ["Hello", "world"] print my_list.join("-") # Produce: "Hello-world" 而不是: my_list = ["Hello

  • 本文向大家介绍String 为什 么是不可变的?相关面试题,主要包含被问及String 为什 么是不可变的?时的应答技巧和注意事项,需要的朋友参考一下 简单的来说:String 类中使用 final 关键字修饰字符数组来保存字符串,`private final char value[]`,所以 String 对象是不可变的。而StringBuilder 与 StringBuffer 都继承自 Ab

  • 问题内容: 这可能是有史以来最愚蠢的问题,但我认为对于Java新手来说,这非常令人困惑。 有人可以澄清什么是不变的吗? 为什么是String一成不变的? 不可变对象的优点/缺点是什么? 为什么诸如StringBuilderString之类的可变对象优先于String,反之亦然? 一个很好的例子(在Java中)将不胜感激。 问题答案: 不可变是指一旦对象的构造函数完成执行,该实例将无法更改。 这很有