O(1)从mutable.Map转换为immutable.Map?

时间:2010-03-17 08:29:13

标签: scala scala-collections

有没有办法在O(1)时间内将可变映射转换(换行)为不可变(也就是说,不是通过复制值,而是类似于在JavaConversions中完成的操作)

6 个答案:

答案 0 :(得分:6)

正如托马斯指出的那样,只读视图是O(1)。但是只读不等同于不变性。

差异在“Fighting Bit Rot”论文中有详细描述:

  

所有集合类都保存在   包scala.collection。这个包   有三个子包:可变,   不可变的,通用的。最   馆藏有三种形式,   取决于他们的可变性。

     

包中的集合   scala.collection.immutable是   保证是不可改变的   大家。这意味着人们可以依靠   访问相同的事实   随时间变化的收集价值将永远   产生一个相同的集合   元素。包中的集合   scala.collection.mutable是众所周知的   有一些改变的操作   收集到位。

     

包中的集合   scala.collection可以是可变的   或不可变的。例如,   collection.Seq [T]是一个超类   collection.immutable.Seq [T]和   collection.mutable.Seq [T]。通常,   包scala中的根集合。   集合定义相同的接口   作为不可变的集合,和   包中的可变集合   scala.collection.mutable通常添加   一些破坏性的修改   这种不可变的操作   接口。 之间的区别   根集合和不可变   集合是一个用户   immutable collection有保证   没人能改变这个集合,   而根集合的用户有   承担他人的修改,   即使他们不能做任何事情   修改自己。

也许这只是一个简单的升级。

scala> val mm = collection.mutable.Map(1 -> 2)
mm: scala.collection.mutable.Map[Int,Int] = Map(1 -> 2)

scala> val readOnly = mm : collection.Map[Int, Int]
readOnly: scala.collection.Map[Int,Int] = Map(1 -> 2)

答案 1 :(得分:3)

可变地图有read only projection

scala> collection.mutable.Map(1->2).readOnly
res0: scala.collection.Map[Int,Int] = ro-Map(1 -> 2)

作为oxbow_lakes pointed out,基础Map仍然是可变的,并且在将只读投影发布到客户端后可能会发生变化。在管理地图的代码中必须解决不可变性的错觉。

答案 2 :(得分:3)

你所要求的本质上是不安全的。您可以将mutable.Map作为不可变的collection.Map传递,但使用此表单的“客户”无法确定其视图是否会从其下方更改。

答案 3 :(得分:3)

原则上可以在可变数据结构中添加“冻结”方法,以防止进一步突变。这是进行包装的唯一更安全的方法。 (只是稍微有点因为在你尝试改变它之后你必须抛出异常。)然而,Scala的可变集合没有这种能力。可以将其添加到例如mutable.HashMap通过覆盖所有变异方法(update+=++=等),但这将是一项相当大的工作。

答案 4 :(得分:2)

Philipp Haller关于Capabilities for Uniqueness and Borrowing的工作与此有关。在通过类型系统强制执行“所有权”的领域还有很多其他工作,但Philipp实际上为Scala编译器提供了一个可用的插件。

答案 5 :(得分:0)

应该做的事情类似于ArraySeq.unsafeWrapArray


class UnsafeWrappedMap[K, V](underlying: mutable.Map[K, V]) extends Map[K, V] with StrictOptimizedMapOps[K, V, Map, Map[K, V]] {
  def removed(key: K) = underlying.iterator.filter(_._1 != key).toMap

  def updated[V1 >: V](key: K, value: V1) = {
    underlying.iterator.map {
      case (`key`, _) => (key, value)
      case kv => kv
    }.toMap
  }

  def get(key: K) = underlying.get(key)

  def iterator = underlying.iterator
}

object UnsafeWrappedMap {
  def apply[K, V](underlying: mutable.Map[K, V]) = new UnsafeWrappedMap(underlying)
}

显然,创建此地图后,您一定不能触摸可变地图!

一个更雄心勃勃的解决方案是创建一个映射,该映射一旦创建副本就设置一个内部标志,任何将来的突变都会导致可变实例在执行突变之前复制其内部状态。