変更可能な Map を O(1) 時間で不変に変換 (ラップ) する方法はありますか (つまり、値をコピーするのではなく、JavaConversions で行われるのと同様です)
6 に答える
Thomas が指摘するように、読み取り専用ビューは O(1) です。ただし、読み取り専用は不変性とは異なります。
この違いについては、" Fighting Bit Rot " ペーパーで詳しく説明されています。
すべてのコレクション クラスはパッケージ scala.collection に保持されます。このパッケージには、mutable、immutable、generic の 3 つのサブパッケージがあります。ほとんどのコレクションは、可変性に応じて 3 つの形式で存在します。
パッケージ scala.collection.immutable のコレクションは、誰に対しても不変であることが保証されています。つまり、時間の経過とともに同じコレクション値にアクセスすると、常に同じ要素を持つコレクションが生成されるという事実を信頼できます。パッケージ scala.collection.mutable のコレクションには、コレクションを変更するいくつかの操作があることが知られています。
パッケージ scala.collection のコレクションは、可変または不変のいずれかです。たとえば、collection.Seq[T] は、collection.immutable.Seq[T] と collection.mutable.Seq[T] の両方のスーパークラスです。通常、パッケージ scala のルート コレクション。コレクションは不変コレクションと同じインターフェースを定義し、パッケージ scala.collection.mutable の可変コレクションは通常、この不変インターフェースにいくつかの破壊的な変更操作を追加します。ルート コレクションと不変コレクションの違いは、不変コレクションのユーザーには誰もコレクションを変更できないという保証があるのに対し、ルート コレクションのユーザーは、自分では変更を行うことができなくても、他のユーザーによる変更を想定する必要があることです。
おそらく、アップキャストのような単純なものです。
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)
変更可能なマップには読み取り専用のプロジェクションがあります。
scala> collection.mutable.Map(1->2).readOnly
res0: scala.collection.Map[Int,Int] = ro-Map(1 -> 2)
oxbow_lakesが指摘したように、基礎となる Map は依然として変更可能であり、読み取り専用プロジェクションがクライアントに公開された後に変更される可能性があります。不変性の錯覚は、マップを管理するコードで対処する必要があります。
あなたが求めているものは本質的に安全ではありません。mutable.Map
を不変の として渡すこともできますが、collection.Map
このフォームを使用する「クライアント」は、ビューがその下から変更されないことを確認できません。
原則として、「フリーズ」メソッドを可変データ構造に追加して、それ以上の変異を防ぐことができます。これは、ラッピングを行う唯一のわずかでも安全な方法です。(後で変更しようとすると例外をスローする必要があるため、ほんのわずかです。) ただし、Scala の変更可能なコレクションにはこの機能がありません。update
たとえば、すべての変更メソッド ( 、+=
、など)をオーバーライドすることで、これを mutable.HashMap に追加できます++=
が、これはかなりの作業になります。
Philipp Haller のCapabilities for Uniqueness and Borrowingに関する研究はこれに関連しています。型システムを通じて「所有権」を強制する領域には他にも多くの作業がありますが、Philipp は実際に Scala コンパイラに使用可能なプラグインを提供しています。