4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

彡(゚)(゚)「KotlinでListにaddできない!なんでや!」(´・ω・`)「それはね」

Last updated at Posted at 2020-06-26

やきうのお兄ちゃんはKotlinで困っていました。

彡(゚)(゚)「なんで高橋由伸を巨人に入れられへんねん!これ以上由伸を苦しめるなや!」

giants.kt
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 // 再割り当てしてしまっているのでエラー

}

(´・ω・`)「こういう関係性になっているよ。混乱してしまうかもしれないけど、じっくり読んでみてね。何回か使えば覚えられるよ。」

彡(゚)(゚)「ほうほうなるほど・・・。でも、 まだコンパイルエラーになっとるぞ! めん玉えぐったる!」

giants.kt
fun main() {

    val giants : List<String> = mutableListOf("阿部")

    giants.add("高橋") // コンパイルエラー
}

(´・ω・`)「うわあああああ待って!」

List型で型宣言してしまっている

(´・ω・`)「これはJavaをこれまでやってきた人がハマる罠だと思う」

彡(゚)(゚)「確かにワイは元々Javaのエンジニアやわ」

(´・ω・`)「結論から言うと、giantsがList型になってるからだよ」

彡(゚)(゚)「なんでやねん、List型で問題ないやんけ」

(´・ω・`)「Javaならね。でもKotlinだと事情が違うんだよ。先に直しちゃうと、giants2giants3の書き方ならOKだよ」

giants.kt
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のリファレンスの中で初めて登場するんだ。」

彡(゚)(゚)「・・・?」

(´・ω・`)「要点を整理するとこうなるよ。」

関係性のイメージ

image.png

(´・ω・`)「変数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頼むで!」
(´^ω^`)「ストックもね!」

4
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?