我是 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]
中使用 Integer
和 String
没有发现任何问题。如何将整数值存储到字符串集合中,如何编写???何为灾难???为什么我应该使用 List(不可变)而不是 ListBuffer(可变)?我没看出任何区别。我找到了很多答案,即可变集合应该具有类型不变,并且不可变集合应该具有协变类型,但为什么呢?
2) 最后一部分“res4: everything.type = ListBuffer(1,裤子)
”是什么意思? “一切类型”是什么意思?我猜想 everything
没有任何名为 type
的方法/函数或变量。为什么没有 ListBuffer[Any] 或 ListBuffer[String]?
非常感谢,
安德鲁
最佳答案
1这看起来不像是一个单一的问题,所以我必须进一步分割它:
- “实际上”
一切
都是ListBuffer[_]
,并且参数类型被删除。根据 JVM,它保存对某些对象的 32 位或 64 位引用。ListBuffer[String]
和ListBuffer[Any]
类型是编译器在编译时所了解的类型。如果它“知道”两个相互矛盾的事情,那么这显然是非常糟糕的。 “我没有发现整数和字符串存在任何问题 一个 ListBuffer[Any]"。
ListBuffer[Any]
中包含Int
和String
没有问题,因为ListBuffer
是不变的。但是,在您的假设示例中,ListBuffer
是协变的,因此您将Int
存储在ListBuffer[String]
。如果后来有人从ListBuffer[String]
获取Int
,并尝试将其解释为String
,那么这显然是非常糟糕的。不好。“如何将整数值存储到集合中 字符串如何编写?”为什么你想做一些显然非常糟糕的事情,如上所述?
“为什么是灾难???”这不会是一场重大灾难。 Java 一直与协变数组共存。它不会导致灾难,只是糟糕且烦人。
“为什么我应该使用 List(不可变)而不是 ListBuffer(可变)?” 没有绝对命令告诉您始终使用
List
并且永远不要使用ListBuffer
。在适当的时候使用两者。在 99.999% 的情况下,List
当然更合适,因为您使用List
来表示数据的方式比设计需要局部可变状态的复杂算法更频繁。ListBuffer
。“我发现了很多可变集合的答案 应该具有类型不变性并且不可变集合应该 具有协变类型,但为什么?”。这是错误的,你过于简化了。例如,内涵不可变集既不应该是协变的,也不应该是不变的,而是逆变。你应该使用协变、逆变和不变性(在适当的时候)。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
关于Scala - 可变集合中的协变类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49410925/