Kotlin varとvalの違い


var と val の違いとは?

  • var : 再代入可能な変数(読み書き可能な変数)
  • val : 読み込み専用の変数

以下のような操作を行った時、valではbuild errorとなります。

class Foo{}
val foo = Foo()
foo = Foo() //変数fooに再度Foo()インスタンス

valについて

いや、valに代入したArrayListの要素を変更できるんですけど?

val foo = arrayListOf(1,2,3)
foo.add(4)

再代入ではく代入したインスタンスを読み込んでいるだけ。val fooを別のインスタンスに変更しようとしているわけではありません。読み込んだインスタンスが何かしらの操作をしているのであって、fooが保持しているArrayListのインスタンスはadd前も後も同じものです。

変数fooが保持しているArrayListが変わるわけではなく、変数fooが保持しているArrayListの中身が変わったとみなせます。

対比として以下をイメージすると理解しやすいかもしれません。

val foo = arrayListOf(1,2,3)
foo.add(4)

//新しいインスタンスを作成して再代入しようとしている為、これではエラーになります
foo = arrayListOf(1,2,3,4)

でもこれでエラーになるんだけど?

foo と bar は同一のインスタンスだよね?

class Foo{}
val foo = Foo()
var bar = foo
foo = bar //エラー

保持しているFoo()インスタンスを同じFoo()インスタンスに変更しようとしているから。

オブジェクトは理解したけどプリミティブ値は?

プリミティブ値も内部的にはオブジェクトなので同様の扱いです。 プリミティブ値に対して、+==の演算子が自然と使えるのは演算子をオーバーロードしているからだと思います。

ループ内でvalを使うと再代入出来るんだけど?

(0..5).forEach {
    val p = Integer.parseInt(it.toString())
}

val 変数のスコープが{ }の間だけだから。

varを使うケース

実はvarを使うシーンはあまりありません。使うケースとしては

インスタンス作成時に参照オブジェクトが決まらないメンバ変数

lateinit varを使う

lateinit var foo:View

計算結果によってプリミティブ値に変化を加える

var i:Int = 0
if( true ){ i++ }

思いつけば追記予定