我是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)
你能发现问题吗?由于所有内容均为“任意”类型,因此您可以存储
将整数值转换为字符串集合。这是一场灾难,等待发生。为避免此类问题,始终
使可变对象不变的好主意。
我将有以下问题。
1)实际上是哪种类型的
everything
? String
或Any
?声明是“val everything: ListBuffer[Any]
”,因此我期望Any
,因为一切都应该是Any
的类型,那么我认为在一个Integer
中包含String
和ListBuffer[Any]
不会出现任何问题。我如何将整数值存储到字符串集合中,它们如何编写???为什么会灾难???为什么要使用List(不可变)而不是ListBuffer(可变)?我没看出任何区别。我发现了很多答案,可变集合应该具有类型不变,而可变集合应该具有协变量类型,但是为什么呢?2)最后一部分“
res4: everything.type = ListBuffer(1, pants)
”是什么意思? “everything.type”是什么意思?我猜everything
没有称为type
的任何方法/函数或变量。为什么没有ListBuffer [Any]或ListBuffer [String]?非常感谢,
安德鲁
最佳答案
1 这看起来不是一个单一的问题,所以我必须进一步细分它:
everything
是ListBuffer[_]
,具有擦除的参数类型。根据JVM,它包含对某些对象的32位或64位引用。编译器在编译时就知道ListBuffer[String]
和ListBuffer[Any]
类型。如果它“知道”两个矛盾的事情,那么显然很糟糕。 一个ListBuffer [Any]”。
Int
中没有String
和ListBuffer[Any]
是没有问题的,因为ListBuffer
是不变的。但是,在您的假设示例中,ListBuffer
是协变的,因此您将Int
存储在ListBuffer[String]
中。 Int
中的ListBuffer[String]
,并尝试将其解释为String
,那么显然很糟糕。如何写字符串?”如上所述,您为什么要做明显很糟糕的事情?
List
而不要使用ListBuffer
。适当时请同时使用两者。在99.999%的情况下,List
当然更合适,因为与设计需要List
局部可变状态的复杂算法相比,使用ListBuffer
表示数据的频率更高。 应该具有不变的类型,并且不可变的集合应该
具有协变类型,但为什么呢?”。这是错误的,您过于简化了。例如,内涵不可变集既不应协变,也不应不变,而应是互变的。在适当的情况下,应使用协方差,协变和不变性。也许您也觉得它有用。
2 这是This little silly illustration has proven unreasonably effective for explaining the difference,就像下面的示例一样:
scala> val x = "hello"
x: String = hello
scala> val y: x.type = x
y: x.type = hello
这是一个singleton type。
关于scala - Scala-可变集合中的协变类型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49410925/