Scala - 可变集合中的协变类型

标签 scala immutability covariance mutability invariance

我是 Scala 世界的新手,现在我正在阅读名为“Scala in Action”(作者 Nilanjan Raychaudhuri)的书,即第 97 页上名为“可变对象需要不变”的部分,我不明白以下部分直接摘自上述书籍。


假设 ListBuffer 是协变的,并且以下代码片段可以正常工作,没有任何编译问题:

scala> val mxs: ListBuffer[String] = ListBuffer("pants")
mxs: scala.collection.mutable.ListBuffer[String] =
ListBuffer(pants)
scala> val everything: ListBuffer[Any] = mxs
scala> everything += 1
res4: everything.type = ListBuffer(1, pants)

你能找出问题所在吗?因为所有内容都是 Any 类型,所以您可以存储 整数值转换为字符串集合。这是一场即将发生的灾难。为了避免此类问题,始终 使可变对象保持不变的好主意。


我有以下问题..

1) 现实中的一切是什么类型? 字符串还是任何?声明是“val everything: ListBuffer[Any]”,因此我期望 Any 并且因为所有内容都应该是 Any 类型,所以我不在一个 ListBuffer[Any] 中使用 IntegerString 没有发现任何问题。如何将整数值存储到字符串集合中,如何编写???何为灾难???为什么我应该使用 List(不可变)而不是 ListBuffer(可变)?我没看出任何区别。我找到了很多答案,即可变集合应该具有类型不变,并且不可变集合应该具有协变类型,但为什么呢?

2) 最后一部分“res4: everything.type = ListBuffer(1,裤子)”是什么意思? “一切类型”是什么意思?我猜想 everything 没有任何名为 type 的方法/函数或变量。为什么没有 ListBuffer[Any] 或 ListBuffer[String]?

非常感谢,

安德鲁

最佳答案

1这看起来不像是一个单一的问题,所以我必须进一步分割它:

  1. “实际上”一切都是ListBuffer[_],并且参数类型被删除。根据 JVM,它保存对某些对象的 32 位或 64 位引用。 ListBuffer[String]ListBuffer[Any] 类型是编译器在编译时所了解的类型。如果它“知道”两个相互矛盾的事情,那么这显然是非常糟糕的。
  2. “我没有发现整数和字符串存在任何问题 一个 ListBuffer[Any]"ListBuffer[Any] 中包含 IntString 没有问题,因为 ListBuffer 是不变的。但是,在您的假设示例中,ListBuffer 是协变的,因此您将 Int 存储在 ListBuffer[String]。如果后来有人从 ListBuffer[String] 获取 Int,并尝试将其解释为 String,那么这显然是非常糟糕的。不好。

  3. “如何将整数值存储到集合中 字符串如何编写?”为什么你想做一些显然非常糟糕的事情,如上所述?

  4. “为什么是灾难???”这不会是一场重大灾难。 Java 一直与协变数组共存。它不会导致灾难,只是糟糕且烦人。

  5. “为什么我应该使用 List(不可变)而不是 ListBuffer(可变)?” 没有绝对命令告诉您始终使用 List 并且永远不要使用 ListBuffer。在适当的时候使用两者。在 99.999% 的情况下,List 当然更合适,因为您使用 List 来表示数据的方式比设计需要局部可变状态的复杂算法更频繁。 ListBuffer

  6. “我发现了很多可变集合的答案 应该具有类型不变性并且不可变集合应该 具有协变类型,但为什么?”。这是错误的,你过于简化了。例如,内涵不可变集既不应该是协变的,也不应该是不变的,而是逆变。你应该使用协变、逆变和不变性(在适当的时候)。This little silly illustration has proven unreasonably effective for explaining the difference,也许你也觉得它很有用。

2 这是 singleton type ,就像下面的例子一样:

scala> val x = "hello"
x: String = hello

scala> val y: x.type = x
y: x.type = hello

这是一个longer discussion about the motivation为此。

关于Scala - 可变集合中的协变类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49410925/

相关文章:

c++ - 如何修改不可变对象(immutable对象)?

java - Jenkins 在 Scala 失败时报告成功

javascript - "with"从 Scala 中的 JavaScript 构造

api - Scala 标准库类型的摘要/引用文档

json - GATLING JSON 保存和重用

memory - 不可变可以是内存 pig 吗?

arrays - 如果 Scala 中需要不可变数组,返回 IndexesSeq 而不是 Array 是否正确?

java - 为什么不能 List<? extends Animal> 被替换为 List<Animal>?

c# - 为什么这个协方差声明可以编译?

r - 在 R 中计算向量值 Hessian