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++ }
思いつけば追記予定
リンク
リンク