在收集的scala文档中,我发现以下声明为:
" 根集合(scala.collection)和不可变集合(scala.collection.immutable)之间的区别是不可变的客户端集合保证没有人可以改变集合,而根集合的客户端只承诺不自己更改集合。尽管此类集合的静态类型不提供修改集合的操作,但运行时类型仍可能是可变集合,可由其他客户端更改。"
但我没有得到这一行," 而根集合的客户只承诺不自行更改集合 ",是说?
答案 0 :(得分:6)
让我们考虑三种可能性:
def foo(it: scala.collection.mutable.Iterable[Int]) = ???
def bar(it: scala.collection.immutable.Iterable[Int]) = ???
def baz(it: scala.collection.Iterable[Int]) = ???
foo
采用可变集合,因此有权修改它。
如果您致电foo
,则必须期望作为调用者,foo
修改该集合(可能不会,但您无法分辨)。您还必须考虑在执行foo
时修改集合的可能性。
bar
采用不可变的集合。这需要两件事:
bar
的来电者:将收藏集传递给bar
将永远不会对其进行修改,我们保证在bar
返回时收藏品将保持完整。bar
本身:在实施bar
主体时可以安全地认为在bar
执行期间收集不会发生变化。 baz
需要" root"采集。与不可变集合不同,只有point(1)成立。换句话说,只有baz
的调用者在此处有任何保证:将集合传递给baz
将永远不会修改它,我们保证在baz
返回时集合将保持不变。
相反,在实施baz
时,我们无法保证在baz
执行时集合不会发生变化,因为baz
本身由于缺少变异而无法修改集合方法" root"集合,该集合仍然可能是可变的,并将被另一个线程修改。
考虑一下:
val buf = collection.mutable.Buffer[Int](1,2,3)
def baz(it: scala.collection.Iterable[Int]) = {
println(it)
Thread.sleep(2000)
println(it)
}
new Thread {
override def run() {
Thread.sleep(1000)
buf += 4
}
}.start()
baz(buf)
结果跟踪:
ArrayBuffer(1, 2, 3)
ArrayBuffer(1, 2, 3, 4)
在上面的代码片段中,我们创建了一个可变集合并将其传递给baz
,期望" root"采集。然后我们会在baz
执行时修改该集合,证明baz
在it
执行时不能依赖FileMode.Append
进行更改。
答案 1 :(得分:2)
基本上,它告诉您作为根集合的客户端,您无法保证您获得了不可变集合。它很可能是一个可变集合子类的实例(它实现了根集合特征)。你不能做的事情(没有强制转换)会改变根集合 - 即使它在运行时实际上是一个可变集合。