简体   繁体   English

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

[英]Scala - covariant type in mutable collections

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. 我是Scala世界的新手,现在我正在阅读称为“ Scala in Action”(由Nilanjan Raychaudhuri撰写)的书,即第97页上的“可变对象需要不变”部分,而我不理解以下内容:直接取自上述书籍。


Assume ListBuffer is covariant and the following code snippet works without any compilation problem: 假设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)

Can you spot the problem? 你能发现问题吗? Because everything is of the type Any, you can store an integer value into a collection of strings. 由于所有内容均为Any类型,因此您可以将整数值存储在字符串集合中。 This is a disaster waiting to happen. 这是一场灾难,等待发生。 To avoid these kinds of problems, it's always a good idea to make mutable objects invariant. 为避免此类问题,使可变对象不变是一个好主意。


I would have the following questions.. 我将有以下问题。

1) What type of everything is in reality? 1)现实中是什么类型的everything String or Any ? String还是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] . 声明是“ val everything: ListBuffer[Any] ”,因此我希望使用Any并且因为一切都应该是Any类型,所以我看不到将IntegerString放在一个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)? 为什么要使用List(不可变)而不是ListBuffer(可变)? 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) What does the last part " res4: everything.type = ListBuffer(1, pants) " mean? 2)最后一部分“ res4: everything.type = ListBuffer(1, pants) ”是什么意思? What does "everything.type" mean? “ everything.type”是什么意思? I guess that everything does not have any method/function or variable called type .. Why is there no ListBuffer[Any] or ListBuffer[String]? 我猜everything都没有任何称为type 。的方法/函数或变量。为什么没有ListBuffer [Any]或ListBuffer [String]?

Thanks a lot, 非常感谢,

Andrew 安德鲁

1 This doesn't look like a single question, so I have to subdivide it further: 1这看起来好像不是一个问题,所以我必须进一步细分它:

  1. "In reality" everything is ListBuffer[_] , with erased parameter type. “实际上” everything都是ListBuffer[_] ,具有擦除的参数类型。 Depending on the JVM, it holds either 32 or 64 bit references to some objects. 根据JVM,它包含对某些对象的32位或64位引用。 The types ListBuffer[String] and ListBuffer[Any] is what the compiler knows about it at compile time. ListBuffer[String]ListBuffer[Any]是编译器在编译时所知道的。 If it "knows" two contradictory things, then it's obviously very bad. 如果它“知道”两个矛盾的事情,那么显然很糟糕。
  2. "I don't see any problems to have Integer and String in one ListBuffer[Any]" . “在一个ListBuffer [Any]中包含Integer和String不会出现任何问题” There is no problem to have Int and String in ListBuffer[Any] , because ListBuffer is invariant. ListBuffer[Any]具有IntString是没有问题的,因为ListBuffer是不变的。 However, in your hypothetical example, ListBuffer is covariant, so you are storing an Int in a ListBuffer[String] . 但是,在您的假设示例中, ListBuffer是协变的,因此您将Int存储在ListBuffer[String] If someone later gets an Int from a ListBuffer[String] , and tries to interpret it as String , then it's obviously very bad. 如果以后有人从ListBuffer[String]获取一个Int并尝试将其解释为String ,那么显然很糟糕。

  3. "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? 如上所述,您为什么要做显然很糟糕的事情?

  4. "Why disaster???" “为什么要灾难???” It wouldn't be a major disaster. 这不会是一场大灾难。 Java has been living with covariant arrays forever. Java一直都在使用协变数组。 It's does not lead to cataclysms, it's just bad and annoying. 它不会导致大灾变,只是不好而且令人讨厌。

  5. "Why should I use List (which is immutable) instead of ListBuffer (which is mutable)?" “为什么我应该使用List(不可变)而不是ListBuffer(可变)?” There is no absolute imperative that tells you to always use List and to never use ListBuffer . 没有绝对的必要条件告诉您始终使用List而不要使用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 . 在99.999%的情况下, List当然更合适,因为与设计需要ListBuffer局部可变状态的复杂算法相比,使用List表示数据的方式更为频繁。

  6. "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 This is a singleton type , just like in the following example: 2这是一个单例类型 ,如以下示例所示:

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

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

Here is a longer discussion about the motivation for this. 这是关于此动机更长时间的讨论

I agree with most of what @Andrey is saying I would just add that covariance and contravariance belong exclusively to immutable structures, the exercisce that the books proposes is just a example so people can understand but it is not possible to implement a mutable structure that is covariant, you won't be able to make it compile. 我同意@Andrey所说的大部分内容,我只是补充说协方差和协方差完全属于不可变的结构,书中提出的练习只是一个例子,人们可以理解,但不可能实现一个可变结构,即协变,则无法对其进行编译。 As an exercise you could try to implement a MutableList[+A] , you'll find out that there is not way to do this without tricking the compiler putting asInstanceOf everywhere 作为练习,您可以尝试实现MutableList[+A] ,您会发现没有asInstanceOf不用欺骗编译器就可以将asInstanceOf放在各处

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM