scala中根集合和不可变集合之间的区别

时间:2016-04-04 09:57:54

标签: scala collections

在收集的scala文档中,我发现以下声明为:

docs here

" 根集合(scala.collection)和不可变集合(scala.collection.immutable)之间的区别是不可变的客户端集合保证没有人可以改变集合,而根集合的客户端只承诺不自己更改集合。尽管此类集合的静态类型不提供修改集合的操作,但运行时类型仍可能是可变集合,可由其他客户端更改。"

但我没有得到这一行," 而根集合的客户只承诺不自行更改集合 ",是说?

2 个答案:

答案 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采用不可变的集合。这需要两件事:

    1. 表示bar的来电者:将收藏集传递给bar将永远不会对其进行修改,我们保证在bar返回时收藏品将保持完整。
    2. 适用于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执行时修改该集合,证明bazit执行时不能依赖FileMode.Append进行更改。

答案 1 :(得分:2)

基本上,它告诉您作为根集合的客户端,您无法保证您获得了不可变集合。它很可能是一个可变集合子类的实例(它实现了根集合特征)。你不能做的事情(没有强制转换)会改变根集合 - 即使它在运行时实际上是一个可变集合。