この記法の意味と、以下のような import 文を記述しなければならない理由がわからなかったので、これらの意味を調べていく。
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
var ... by ...
とは
委譲プロパティと呼ばれるもの。この構文を使うためには、Foo
クラスに getValue(Nothing?, KProperty<*>): T
と setValue(Nothing?, KProperty<*>, value: T)
を実装する必要がある。
import kotlin.reflect.KProperty
class Foo {
operator fun getValue(a: Nothing?, b: KProperty<*>): Int {
return 1
}
operator fun setValue(a: Nothing?, b: KProperty<*>, value: Int) {
}
}
fun main() {
var foo by Foo()
println(foo) //=> 1
foo = 2
println(foo) //=> 1
}
foo
は Int 型にも関わらず、式評価時と代入時には getValue()
と setValue()
が実行される。プロパティに似ている。
まとめると、次のような構造をしていることがわかる。
var foo/* 変数名 */ by Foo()/* getValueとsetValueを持つオブジェクト */
var count by remember { mutableStateOf(0) }
とは
これを var count by remember { mutableStateOf(0) }
に当てはめる。
-
count
: 変数名 -
remember { mutableStateOf(0) }
:getValue
とsetValue
を持つオブジェクト
remember { mutableStateOf(0) }
は MutableState<Int>
型のインスタンスを返す関数の呼び出しである。MutableState<Int>
とそのインタフェースである State<T>
はそれぞれ次のように定義されている。
package androidx.compose.runtime
@Stable
interface State<out T> {
val value: T
}
@Stable
interface MutableState<T> : State<T> {
override var value: T
operator fun component1(): T
operator fun component2(): (T) -> Unit
}
var count by remember { ... }
といった記述を行うために必要な getValue
と setValue
の定義が見当たらない。これらのメソッドは拡張関数として定義されている。
package androidx.compose.runtime
@Suppress("NOTHING_TO_INLINE")
inline operator fun <T> State<T>.getValue(thisObj: Any?, property: KProperty<*>): T = value
@Suppress("NOTHING_TO_INLINE")
inline operator fun <T> MutableState<T>.setValue(thisObj: Any?, property: KProperty<*>, value: T) {
this.value = value
}
よって、var count by remember { ... }
と書くためには次の import 文を追加する必要がある。
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
まとめ
-
var A by B
という記法は委譲プロパティと呼ばれるもので、B
はgetValue
とsetValue
を持つオブジェクトでなければならない -
remember { mutableStateOf(0) }
はMutableState<T>
型のインスタンスを返すが、この型とそのインタフェースであるState<T>
自体にはgetValue
とsetValue
の定義が含まれていない。これらは拡張関数として定義されており、androidx.compose.runtime.getValue
とandroidx.compose.runtime.setValue
をインポートすることで使えるようになる