【问题标题】:Difference between root collections and immutable collection in scalascala中根集合和不可变集合之间的区别
【发布时间】:2016-07-23 19:28:53
【问题描述】:

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

docs here

"根集合 (scala.collection) 和不可变集合 (scala.collection.immutable) 的区别在于,不可变集合的客户端具有保证没有人可以改变集合,而根集合的客户端只承诺不会自己更改集合。即使此类集合的静态类型不提供修改集合的操作,运行时仍有可能type 是一个可变集合,可以被其他客户端更改。 "

但我没听懂这句话,“而根集合的客户只承诺不会自己更改集合”,这是在说什么?

【问题讨论】:

    标签: scala collections


    【解决方案1】:

    让我们考虑三种可能性:

    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 修改(它可能不会,但您无法判断)。作为实施者,您还必须考虑在fooexecutes 时修改集合的可能性。

    • bar 采用不可变集合。这需要两件事:

      1. 对于bar 的调用者:将集合传递给bar 将永远不会修改它,我们保证当bar 返回时集合将保持不变。
      2. 对于bar 本身:在实现bar 的主体时,理所当然地认为集合在bar 执行时不会更改是安全的。
    • baz 采用“根”集合。与不可变集合不同,只有第 (1) 点成立。换句话说,只有baz 的调用者在这里有任何保证:将集合传递给baz 将永远不会修改它,并且我们保证当baz 返回时集合将是完整的。 相反,在实现baz 时,我们不能保证集合在baz 执行时不会改变,因为虽然baz 本身由于“根”集合上缺少变异方法而无法修改集合,但它仍然有可能该集合实际上是可变的并且将被另一个线程修改。

    考虑一下:

    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)
    

    在上面的 sn-p 中,我们创建了一个可变集合并将其传递给baz,它需要一个“根”集合。然后我们在baz 执行时修改集合,证明baz 不能依赖it 在执行时不改变。

    【讨论】:

    • 很好的例子解释,谢谢
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2017-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-24
      • 2018-10-23
      • 1970-01-01
      • 2012-01-07
      • 2015-03-29
      相关资源
      最近更新 更多