有没有办法在O(1)时间内将可变映射转换(换行)为不可变(也就是说,不是通过复制值,而是类似于在JavaConversions中完成的操作)
答案 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)
}
显然,创建此地图后,您一定不能触摸可变地图!
一个更雄心勃勃的解决方案是创建一个映射,该映射一旦创建副本就设置一个内部标志,任何将来的突变都会导致可变实例在执行突变之前复制其内部状态。