可変コレクションと不変コレクション | 目次 |
Scalaのコレクションでは可変コレクションと不変コレクションを系統だって区別します。 可変コレクションは直接変更したり拡張したりできます。 つまり副作用としてコレクションの要素の変更・追加・削除ができるということです。 不変コレクションは対照的に決して変化しません。 追加や削除や更新をシミュレートする演算はありますが、それらの演算は1回ごとに新しいコレクションを返し、古いコレクションは変更しないままにします。
全てのコレクションクラスはscala.collectionパッケージか、 そのサブパッケージmutable, immutable, genericの1つに属します。 クライアントコードで必要となるほとんどのコレクションクラスは3通りの別種があり、 それぞれscala.collection, scala.collection.immutable, およびscala.collection.mutableパッケージに属します。 それぞれの別種は可変性に関して異なる性質を持ちます。
scala.collection.immutableパッケージにあるコレクションはどのオブジェクトから見ても不変であると保障されています。 このようなコレクションは作られた後は決して変化しません。 そのため、同じコレクションに対して複数の場所から繰り返しアクセスしても同じ要素を持つコレクションが常に得られるという事実に依存できます。
scala.collection.mutableパッケージにあるコレクションはコレクションを直接変更できる演算を持つと知られています。そのため可変コレクションを扱う場合はどのコードがいつコレクションを変更するのか把握する必要があります。
scala.collectionパッケージのコレクションは可変でも不変でもありえます。 例えば collection.IndexedSeq[T] は collection.immutable.IndexedSeq[T] と collection.mutable.IndexedSeq[T] の両方の親クラスです。 一般的にはscala.collectionにあるルートコレクションは不変コレクションと同じインターフェースを定義し、scala.collection.mutable内にある可変コレクションは副作用のある変更演算をこの不変インターフェースに追加します。
ルートコレクションと不変コレクションの違いは、不変コレクションを利用する側はコレクションを誰も変更できないと保障されているのに対して、ルートコレクションを利用する側は自分では変更しないと約束するだけである点です。 ルートコレクションの静的な型はコレクションを変更する演算を提供しませんが、それでも実行時の型は他の利用者が変更できる可変コレクションである可能性があります。
デフォルトではScalaでは不変コレクションを利用します。 例えばSetをどこからもインポートせずに、プレフィックスも付けずにSetと単に書くと不変な集合になり、Iterableと書けば不変なイテレータブルコレクションとなります。 これはそれらがscalaパッケージからインポートされるデフォルトのバインディングだからです。 可変なものが欲しい場合はcollection.mutable.Setやcollection.mutable.Iterableと明示する必要があります。
可変版のコレクションと不変版のコレクションの両方が欲しいときは単にscala.collection.mutableパッケージをインポートするのが便利な慣例です。
import scala.collection.mutable
するとSetのようなプレフィックスの無い単語は依然として不変コレクションを指しますが、mutable.Setは可変版を指します。
コレクション階層の最後のパッケージはcollection.genericです。 このパッケージにはコレクションを実装するためのパーツが含まれています。 典型的にはコレクションクラスは演算の一部の実装をgenericパッケージ内のクラスに譲ります。 一方でコレクションフレームワークの利用者がgenericパッケージ内のクラスを参照する必要があるのは例外的な場合のみでしょう。
利便性と互換性のためにいくつかの重要な型はscalaパッケージ内にエイリアスがあるので、インポートせずに単純な名前で利用できます。 Listはその例で、以下のいずれかでもアクセスできます。
scala.collection.immutable.List | 定義されている場所 |
scala.List | scalaパッケージ内のエイリアス経由 |
List | scala._は常にインポートされているため |
同じようにエイリアスがあるその他のクラスは、Traversable, Iterable, Seq, IndexedSeq, Iterator, Stream, Vector, StringBuilder, そしてRangeです。
以下にscala.collection内の全てのコレクションを示します。 これはは全て高水準の抽象クラスまたはトレイトであり、一般に可変な実装も不変な実装も備えます。
以下にscala.collection.immutable内の全てのコレクションを示します。
(訳注: 細い線は継承関係、太い線はデフォルト実装、点線は暗黙のうちに変換可能であることを示す)
そして以下にscala.collection.mutable内の全てのコレクションを示します。
(これらの3つの図は全てdecodified.comのMatthiasが作成しました)。
続いては: コレクションAPIの概要
可変コレクションと不変コレクション | 目次 |