集合(Set)はイミュータブル版とミュータブル版があるんだよ

名前空間が違うので完全名は違うけど以下の2つがある

  1. scala.collection.immutable.Set
  2. scala.collection.mutable.Set

ちなみに普通に初期化してしまうと、問答無用でイミュータブル版になるので注意。

イミュータブル版は要素の追加に注意が必要

その前にまずミュータブル版の追加方法を見る。

scala> import scala.collection.mutable.Set
import scala.collection.mutable.Set

scala> val mutableSet = Set("Mutable", "Set")
mutableSet: scala.collection.mutable.Set[java.lang.String] = Set(Set, Mutable)

scala> mutableSet += "AddValue"

scala> println(mutableSet)
Set(Set, Mutable, AddValue)

ミュータブルオブジェクトなので初期化時にvalでOK。
続いてイミュータブル版、まず同じように書いてみる。

scala> import scala.collection.immutable.Set
import scala.collection.immutable.Set

scala> val immutableSet = Set("Immutable", "Set")
immutableSet: scala.collection.immutable.Set[java.lang.String] = Set(Immutable, Set)

scala> immutableSet += "AddValue"
<console>:7: error: reassignment to val
       immutableSet += "AddValue"
                    ^

という感じに失敗してしまいます。

「+=」の扱いの違い

同じように「+=」を使いましたが、コンパイラはその動作を変えます。
まず、ミュータブルなSetに関してはそのまま「+=」というメソッドを持ちます。つまり、

scala> mutableSet.+=("AddValue2")

という書き方ができます。
対してイミュータブルなSetは「+=」というメソッドを持ちません。ではどうなっているのか、以下のように展開されています。

immutableSet = immutableSet + "AddValue"

そうです。再代入されているだけなのです。ここで引っかかるのは初期化時のvalですね。再代入不可のvalを使ったので失敗してしまったのですよ。
つまり、以下のようにすれば大丈夫です。

scala> var immutableSet2 = Set("Immutable", "Set")
immutableSet2: scala.collection.immutable.Set[java.lang.String] = Set(Immutable, Set)
                     ^
scala> immutableSet2 += "AddValue"

scala> println(immutableSet2)
Set(Immutable, Set, AddValue)

> Scala スケーラブルプログラミング - 第03章