Scala-可变集合中的协变类型 [英] Scala - covariant type in mutable collections
问题描述
我是Scala世界中的新手,现在我正在阅读名为《 Scala in Action》(由Nilanjan Raychaudhuri撰写)的书,即第97页上的"Mutable object必须是不变的"部分,我不理解以下部分直接取自上述书籍.
I am new in Scala world and now I am reading the book called "Scala in Action" (by Nilanjan Raychaudhuri), namely the part called "Mutable object need to be invariant" on page 97 and I don't understand the following part which is taken directly from the mentioned book.
假设ListBuffer是协变的,并且以下代码段可以正常工作,而不会出现任何编译问题:
Assume ListBuffer is covariant and the following code snippet works without any compilation problem:
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)
您能发现问题吗?由于所有内容均为任意"类型,因此您可以存储 将整数值转换为字符串集合.这是一场灾难,等待发生.为避免此类问题,始终 使可变对象不变的好主意.
Can you spot the problem? Because everything is of the type Any, you can store an integer value into a collection of strings. This is a disaster waiting to happen. To avoid these kinds of problems, it’s always a good idea to make mutable objects invariant.
我会有以下问题.
1)实际上是什么类型的everything
? String
还是Any
?声明为"val everything: ListBuffer[Any]
",因此我希望使用Any
,并且由于所有内容都应为Any
类型,所以我看不到将Integer
和String
放在一个ListBuffer[Any]
中的任何问题.我如何将整数值存储到字符串集合中,它们是如何编写的???为什么会灾难???为什么要使用List(不可变)而不是ListBuffer(可变)?我没看见有分别.我发现很多答案,可变集合应该具有类型不变,而可变集合应该具有协变量类型,但是为什么呢?
1) What type of everything
is in reality? String
or Any
? The declaration is "val everything: ListBuffer[Any]
" and hence I would expect Any
and because everything should be type of Any
then I don't see any problems to have Integer
and String
in one ListBuffer[Any]
. How can I store integer value into collection of strings how they write??? Why disaster??? Why should I use List (which is immutable) instead of ListBuffer (which is mutable)? I see no difference. I found a lot of answers that mutably collections should have type invariant and that immutable collections should have covariant type but why?
2)最后一部分"res4: everything.type = ListBuffer(1, pants)
"是什么意思? "everything.type"是什么意思?我想everything
没有名为type
的任何方法/函数或变量.为什么没有ListBuffer [Any]或ListBuffer [String]?
2) What does the last part "res4: everything.type = ListBuffer(1, pants)
" mean? What does "everything.type" mean? I guess that everything
does not have any method/function or variable called type
.. Why is there no ListBuffer[Any] or ListBuffer[String]?
非常感谢
安德鲁
推荐答案
1 这看起来不是一个单一的问题,因此我必须对其进行进一步细分:
1 This doesn't look like a single question, so I have to subdivide it further:
- 实际上"
everything
是ListBuffer[_]
,参数类型已删除.根据JVM,它包含对某些对象的32位或64位引用.类型ListBuffer[String]
和ListBuffer[Any]
是编译器在编译时所知道的.如果它知道"两个矛盾的事情,那么显然很糟糕. -
在使用Integer和String时,我看不到任何问题 一个ListBuffer [Any]".在
ListBuffer[Any]
中包含Int
和String
是没有问题的,因为ListBuffer
是不变的.但是,在您的假设示例中,ListBuffer
是协变的,因此您正在将Int
存储在ListBuffer[String]
中.如果以后有人从ListBuffer[String]
获取Int
,并试图将其解释为String
,那么显然很糟糕.
- "In reality"
everything
isListBuffer[_]
, with erased parameter type. Depending on the JVM, it holds either 32 or 64 bit references to some objects. The typesListBuffer[String]
andListBuffer[Any]
is what the compiler knows about it at compile time. If it "knows" two contradictory things, then it's obviously very bad. "I don't see any problems to have Integer and String in one ListBuffer[Any]". There is no problem to have
Int
andString
inListBuffer[Any]
, becauseListBuffer
is invariant. However, in your hypothetical example,ListBuffer
is covariant, so you are storing anInt
in aListBuffer[String]
. If someone later gets anInt
from aListBuffer[String]
, and tries to interpret it asString
, then it's obviously very bad.
如何将整数值存储到集合中 字符串是怎么写的?" 为什么您要做如上所述显然很糟糕的事情?
"How can I store integer value into collection of strings how they write?" Why would you want to do something that is obviously very bad, as explained above?
为什么会发生灾难?" 这不会是大灾难. Java一直都在使用协变数组.它不会导致大灾变,只是很糟糕而且很烦人.
"Why disaster???" It wouldn't be a major disaster. Java has been living with covariant arrays forever. It's does not lead to cataclysms, it's just bad and annoying.
为什么我应该使用List(不可变)而不是ListBuffer(可变)?" 没有绝对的必要条件告诉您始终使用List
并永远不要使用ListBuffer
.适当时请同时使用两者.在99.999%的情况下,List
当然更合适,因为与设计需要ListBuffer
局部可变状态的复杂算法相比,使用List
表示数据的频率更高.
"Why should I use List (which is immutable) instead of ListBuffer (which is mutable)?" There is no absolute imperative that tells you to always use List
and to never use ListBuffer
. Use both when it is appropriate. In 99.999% of cases, List
is of course more appropriate, because you use List
s to represent data way more often than you design complicated algorithms that require local mutable state of a ListBuffer
.
我发现了很多可变的答案 应该具有类型不变性,并且不可变的集合应该 具有协变类型,但为什么呢?" .这是错误的,您过于简化了.例如,内涵不可变集既不应该协变也不应该不变,而应该是 contravariant .您应该使用协变这个小小的愚蠢的例子被证明对解释这种差别是不合理的有效,也许你也发现了它很有用.
"I found a lot of answers that mutably collections should have type invariant and that immutable collections should have covariant type but why?". This is wrong, you are over-simplifying. For example, intensional immutable sets should be neither covariant, nor invariant, but contravariant. You should use covariance, contravariance, and invariance when it's appropriate. This little silly illustration has proven unreasonably effective for explaining the difference, maybe you too find it useful.
2 这是单例类型,如以下示例所示:
2 This is a singleton type, just like in the following example:
scala> val x = "hello"
x: String = hello
scala> val y: x.type = x
y: x.type = hello
这篇关于Scala-可变集合中的协变类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!