やきうのお兄ちゃんはKotlinで困っていました。
彡(゚)(゚)「なんで高橋由伸を巨人に入れられへんねん!これ以上由伸を苦しめるなや!」
fun main() {
val giants : List<String> = listOf("阿部")
giants.add("高橋") // コンパイルエラー
}
(´・ω・`)「どうしたの?」
mutable~Of()を使っているか?
(´・ω・`)「Kotlinでは listOf()
mapOf()
setOf()
らの関数は 読み取り専用 のコレクションを返すんだ。だから書き込みである add()
はできないんだよ。」
彡(゚)(゚)「ほんならどうやって書き込むねん」
(´・ω・`)「書き込み可能なコレクションに変えれば大丈夫だよ、mutableListOf
mutableMapOf
mutableSetOf
関数を使おうね。」
彡(゚)(゚)「var
とかval
とかあるやん、あれと違うんか?」
(´・ω・`)「いい質問だね。でもちょっと違うよ。そこが、変更不可 ではなく 読み取り専用 とわざわざ言う必要がある理由なんだ。var
はあくまで再割り当てが可能、val
は再割り当てが不可能という特徴を持つよ。詳しくはコードを見たほうが早いね!」
fun main() {
// 再割り当てテスト用のリスト
var list0 = mutableListOf<Int>()
// var 再割り当て OK / murableListOf 要素の書き込み OK
var listA = mutableListOf<Int>(1)
listA.add(2) // エラーにならない
listA = list0 // エラーにならない
// var 再割り当て NG / murableListOf 要素の書き込み OK
val listB = mutableListOf<Int>(1)
listB.add(2) // エラーにならない
listB = list0 // 再割り当てしてしまっているのでエラー
// var 再割り当て OK / murableListOf 要素の書き込み NG
var listC = listOf<Int>(1)
listC.add(2) // コレクションに書き込んでいるのでエラー
listC = list0 // エラーにならない
// var 再割り当て NG / murableListOf 要素の書き込み NG
// いうなれば、こいつが変更不可
val listD = listOf<Int>(1)
listD.add(2) // コレクションに書き込んでいるのでエラー
listD = list0 // 再割り当てしてしまっているのでエラー
}
(´・ω・`)「こういう関係性になっているよ。混乱してしまうかもしれないけど、じっくり読んでみてね。何回か使えば覚えられるよ。」
彡(゚)(゚)「ほうほうなるほど・・・。でも、 まだコンパイルエラーになっとるぞ! めん玉えぐったる!」
fun main() {
val giants : List<String> = mutableListOf("阿部")
giants.add("高橋") // コンパイルエラー
}
(´・ω・`)「うわあああああ待って!」
List型で型宣言してしまっている
(´・ω・`)「これはJavaをこれまでやってきた人がハマる罠だと思う」
彡(゚)(゚)「確かにワイは元々Javaのエンジニアやわ」
(´・ω・`)「結論から言うと、giants
がList型になってるからだよ」
彡(゚)(゚)「なんでやねん、List型で問題ないやんけ」
(´・ω・`)「Javaならね。でもKotlinだと事情が違うんだよ。先に直しちゃうと、giants2
とgiants3
の書き方ならOKだよ」
fun main() {
val giants : List<String> = mutableListOf("阿部")
val giants2 : MutableList<String> = mutableListOf("阿部")
val giants3 = mutableListOf("阿部")
giants.add("高橋") // コンパイルエラー
giants2.add("高橋") // OK
giants3.add("高橋") // OK
}
彡(゚)(゚)「MutableListという型があるんか!」
(´・ω・`)「そうなんだ。JavaだとList型の変数に読み取り専用なList、書き込み可能なListを入れることが多いと思う。だから引っかかるんだ。」
(´・ω・`)「これはListとMutableListの関係がわかると、すんなり理解できるよ。」
Listインターフェイスのリファレンス
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/
MutableListインターフェイスのリファレンス
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-list/
(´・ω・`)「Listのリファレンスの中で、addという関数はあるか見てみてほしい。すると、ないんだ。Listを継承するMutableListのリファレンスの中で初めて登場するんだ。」
彡(゚)(゚)「・・・?」
(´・ω・`)「要点を整理するとこうなるよ。」
関係性のイメージ
(´・ω・`)「変数giants
はList型だから、MutableListの親という関係になる。だからMutableListのインスタンス(※1)を格納できるんだ。でもList型はaddメソッドがないから呼べない。だからエラーになるんだね。」
彡(゚)(゚)「おー、なんとなくわかったわ」
※1 正確にはmutableListOf()メソッドで生成されるのはMutableListインターフェイス型に入ったJavaのArrayListクラスのインスタンスだよ。
ソース kotlin-stdlib-sources.jar!/common/kotlin/collections/Collections.kt:105
動くようになったかな?
彡(゚)(゚)「つまり、こうやな?」
fun main() {
val giants = mutableListOf("阿部")
giants.add("高橋") // OK!
}
(´・ω・`)「そうそう、それで無事実行できるようになったね!」
おわり
良いKotlinライフを!
彡(^)(^) 「LGTM頼むで!」
(´^ω^`)「ストックもね!」