Kotlinのコレクションは「不変」と「可変」に分かれていない
Kotlinのコレクションライブラリに関する解説として、よく、
Kotlinのコレクションは不変と可変に分かれていて〜
といった形のものを見かけます。そして、その例として、
val list: List<Int> = listOf(1, 2, 3) list.add(4) // コンパイルエラー
のようなコードが挙げられていたりします(このような解説を結構見かけるということで、特定の誰かを想定しているわけではありません)。しかし、これは誤りです。以下のコードを実行することで、Kotlinのコレクションの、一見「不変」っぽい型は単に「読み取り専用」の型でしかないことがわかります。
val list1: MutableList<Int> = mutableListOf(1, 2, 3) val list2: List<Int> = list1 list1[0] = 4 println(list2) // list2が「不変」なら [1, 2, 3] になるはずだが、実際は [4, 2, 3]
最後の行のコメントに說明を書いてありますが、これが全てです。「可変」コレクションを「読み取り専用」の型に代入しても、「可変」コレクションの方を変更してしまうと、その変更は「読み取り専用」の型に代入したコレクションにも波及します。
一見、不変にみえるものが単なる読み取り専用でしかない(ことがある)ので、たとえば、以下のようなコードで
fun setParams(params: List<String>) { this.params = params }
フィールドにうかつに読み取り専用コレクションを代入すると、あとでフィールドの値が変わってしまうことがあります。そのため、場合によっては、防御的コピーを作成する等の手段を講じる必要があるでしょう。
この誤解は本当に頻繁に見かけるので、注意しましょう。