2016-06-29 4 views
2

なぜscala.collection.immutable.SortedMapscala.collection.immutable.TreeMapを突然変異させることができますか?またなぜimmutable.SortedMapとimmutable.TreeMapを変更することが可能ですか?

scala> import scala.collection.immutable.SortedMap 
import scala.collection.immutable.SortedMap 

scala> var sm = SortedMap(3 -> 'x', 1 -> 'x', 4 -> 'x') 
sm: scala.collection.immutable.SortedMap[Int,Char] = Map(1 -> x, 3 -> x, 4 -> x) 

scala> sm += (2 -> 'x') 

scala> sm 
res1: scala.collection.immutable.SortedMap[Int,Char] = Map(1 -> x, 2 -> x, 3 -> x, 4 -> x) 

、私は

http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.SortedMap

http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.TreeMap

+=の定義に表示されていないので、どのようにそれは存在しませんか?

+0

あなたはこのScalaの動作によって混乱した唯一の人ではありません - http://bruceeckel.github.io/2014/12/30/operator-underloading-in-scala/ –

答えて

3

不変のコレクションが機能するのは、要素を追加、削除、または変更する操作が、代わりにヒープ上に新しいコレクションを作成することです。したがって、SortedMapへの参照を保持する複数の変数がある場合、変更した変数以外の変数は、元のコレクションを参照し、修正されたバージョンは参照しません。 (これは重要であり、不変なコレクションから得ようとする主な利点の1つは、安全なマルチスレッドと並列化です。)

「新しいコレクションを作成する」と言っても、多くの要素がコピーされます。効率のため、可能であればヒープ上の同じオブジェクトを参照します。これらの共有要素の1つを変更するとすぐに、2つのコレクションが同じ要素を参照しなくなるため、この共有はユーザーにはほとんど見えません(パフォーマンス上の利点以外)。 Scalaの不変なコレクションは一般的に、可能な限りコレクションをほとんどコピーせずに変更を行うことができるように設計されています。 smによって参照されるコレクションへのこの種の変更は、smとというよりvalと宣言したためにのみ可能であったことにも注意してください。新しいコレクションを返すことによってのみコレクションを「変更する」ため、変数に格納されている参照が変更されなければなりません。対照的に、変更可能なコレクションはその場で変更することができるので、smvalと宣言されていても、smによって参照されるコレクションを変更することができます。

sm +=がどこに定義されているのかについては、sm = sm +の構文砂糖です。式sm + (2 -> 'x')は、この要素を追加した結果の新しいコレクションへの参照を返し、この参照はsmに割り当てられます。

+0

あなたは "これらの共有要素の1つを変更すると、2つのコレクションは同じ要素を参照しなくなります。 - どのように達成されたのですか?なぜ私はそれをこのように動作させたいのでしょうか? – rapt

+0

@rapt参照(ポインタ)を更新することによって、基本的に。たとえば、各ノードがその子への参照を保持するバイナリツリーを持っているとします。ツリーの左側のノードを変更する場合は、新しい左側のノードへの参照を保持する新しいトップレベルノードを作成する必要がありますが、同じ右辺のノードへの参照を保持できます。手の側。これにより、ツリーの右端全体をコピーする必要がなくなります。 (実際には、左には変更されたノードを参照しないので、コピーを必要としないサブツリーも存在することがあります)。 –

+0

重要なことは、あなたがやることから得られるセマンティクスを本質的に持つことですディープコピー(元のコレクションへの参照はその同じ非変換コレクションを指しているという意味で)ですが、ディープコピーを実行するパフォーマンスコストはありません。 –

6

実際には、+=の操作は、オリジナル(追加の場合は+演算子)に加えて、再割り当て(元の変数varです)。だから、この可変マップを見て、比較のために

scala> val sm3 = SortedMap(3 -> 'x', 1 -> 'x', 4 -> 'x') 
sm3: scala.collection.immutable.SortedMap[Int,Char] = Map(1 -> x, 3 -> x, 4 -> x) 

scala> sm3 += (2 -> 'x') 
<console>:10: error: value += is not a member of scala.collection.immutable.SortedMap[Int,Char] 
       sm3 += (2 -> 'x') 

:あなたはヴァルを使用しようとすることで、これを見ることができます

scala> var sm2 = SortedMap(3 -> 'x', 1 -> 'x', 4 -> 'x') 
sm2: scala.collection.immutable.SortedMap[Int,Char] = Map(1 -> x, 3 -> x, 4 -> x) 

scala> sm2 = sm2 + (2 -> 'x') 
sm2: scala.collection.immutable.SortedMap[Int,Char] = Map(1 -> x, 2 -> x, 3 -> x, 4 -> x) 

scala> import scala.collection.immutable.SortedMap 
import scala.collection.immutable.SortedMap 

scala> var sm = SortedMap(3 -> 'x', 1 -> 'x', 4 -> 'x') 
sm: scala.collection.immutable.SortedMap[Int,Char] = Map(1 -> x, 3 -> x, 4 -> x) 

scala> sm += (2 -> 'x') 

scala> sm 
res1: scala.collection.immutable.SortedMap[Int,Char] = Map(1 -> x, 2 -> x, 3 -> x, 4 -> x) 

はと同等です

scala> val sm4 = scala.collection.mutable.Map[Int, Char](1 -> 'x') 
sm4: scala.collection.mutable.Map[Int,Char] = Map(1 -> x) 


scala> sm4.put(2, 'x') 
res6: Option[Char] = None 

scala> sm4 
res7: scala.collection.mutable.Map[Int,Char] = Map(2 -> x, 1 -> x) 

ここでは、 valマップの内容です。オブジェクトが変更可能な場合にのみ行うことができます。

+0

Gotcha、私は 'sm'が' var'として定義されたという事実を見落としました。実際には私はScalaで '+ ='のような構文を明示的にメソッドとして定義しなければならないと考えていました。これは 'mutable.Set'のように見ました - なぜこのクラスは' + = '、' ++ = '、' - = '、' - = '?構文的な砂糖機能はどのように機能しますか?また、 'SortedMap'をインスタンス化すると' TreeMap'が返されるので、コマンドラインが作成されたインスタンスを明示的に 'TreeMap'(単に' Map')として表示しないのはなぜですか?私が得るインスタンスは? – rapt

+1

これは既に何度も尋ねられ、回答されています。 'a + = b'がタイプチェックではなく' a = a + b'の場合、コンパイラは前者を後者に書き換えます。 –

+0

ありがとう@JörgWMittag。 –

関連する問題