为什么可以改变scala.collection.immutable.SortedMap
和scala.collection.immutable.TreeMap
?
scala> import scala.collection.immutable.SortedMap
import scala.collection.immutable.SortedMap
scala> var sm = SortedMap(3 -> 'x', 1 -> 'x', 4 -> 'x')
sm: scala.collection.immutable.SortedMap[Int,Char] = Map(1 -> x, 3 -> x, 4 -> x)
scala> sm += (2 -> 'x')
scala> sm
res1: scala.collection.immutable.SortedMap[Int,Char] = Map(1 -> x, 2 -> x, 3 -> x, 4 -> x)
另外,我没有看到
https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
和
http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.SortedMap
+=
的定义,它是如何存在的?
答案 0 :(得分:6)
我同意语法使它看起来像是在改变对象,但实际上+=
操作只是语法糖,用于添加原始语句(使用+
运算符)然后重新分配(当原始变量为var
时)。所以:
scala> import scala.collection.immutable.SortedMap
import scala.collection.immutable.SortedMap
scala> var sm = SortedMap(3 -> 'x', 1 -> 'x', 4 -> 'x')
sm: scala.collection.immutable.SortedMap[Int,Char] = Map(1 -> x, 3 -> x, 4 -> x)
scala> sm += (2 -> 'x')
scala> sm
res1: scala.collection.immutable.SortedMap[Int,Char] = Map(1 -> x, 2 -> x, 3 -> x, 4 -> x)
相当于:
scala> var sm2 = SortedMap(3 -> 'x', 1 -> 'x', 4 -> 'x')
sm2: scala.collection.immutable.SortedMap[Int,Char] = Map(1 -> x, 3 -> x, 4 -> x)
scala> sm2 = sm2 + (2 -> 'x')
sm2: scala.collection.immutable.SortedMap[Int,Char] = Map(1 -> x, 2 -> x, 3 -> x, 4 -> x)
你可以通过尝试使用val:
来看到这一点scala> val sm3 = SortedMap(3 -> 'x', 1 -> 'x', 4 -> 'x')
sm3: scala.collection.immutable.SortedMap[Int,Char] = Map(1 -> x, 3 -> x, 4 -> x)
scala> sm3 += (2 -> 'x')
<console>:10: error: value += is not a member of scala.collection.immutable.SortedMap[Int,Char]
sm3 += (2 -> 'x')
要进行比较,请查看此可变地图:
scala> val sm4 = scala.collection.mutable.Map[Int, Char](1 -> 'x')
sm4: scala.collection.mutable.Map[Int,Char] = Map(1 -> x)
scala> sm4.put(2, 'x')
res6: Option[Char] = None
scala> sm4
res7: scala.collection.mutable.Map[Int,Char] = Map(2 -> x, 1 -> x)
在这里,我们可以更改val
地图的内容,只有在对象可变的情况下才能执行此操作。
答案 1 :(得分:3)
不可变集合的工作方式是添加,删除或修改元素的操作在堆上创建新集合。因此,如果有多个变量引用了您的SortedMap
,那么除了您修改的变量之外的其他变量仍将引用您的原始集合,而不是修改后的版本。 (这很重要,因为人们希望从不可变集合中获得的主要好处之一是安全的多线程和并行化。)
请注意,虽然我说“创建一个新集合”,但可能不需要复制许多元素。为了提高效率,他们将尽可能在堆上引用相同的对象。这种共享对用户来说基本上是不可见的(性能优势除外),因为只要您更改其中一个共享元素,这两个集合就不再引用相同的元素。 Scala的不可变集合通常被设计为可以在尽可能少地复制集合的同时完成修改。
另请注意,这种对sm
引用的集合的修改是可能的,因为您将sm
声明为var
,而不是val
。由于您只是通过返回新集合来“修改”集合,因此存储在变量中的引用必须更改。相反,可以修改可变集合,因此在这种情况下,即使sm
被声明为sm
,您也可以更改val
引用的集合。
关于sm +=
定义位置的问题,它是sm = sm +
的语法糖。表达式sm + (2 -> 'x')
返回对添加此元素所产生的新集合的引用,然后将此引用分配给sm
。