私はこれが大好きですSwift構文;それは多くのことに非常に役立ちます:
var foo: Bar = Bar() {
willSet {
baz.prepareToDoTheThing()
}
didSet {
baz.doTheThing()
}
}
これをコトリンでやりたいです。ただし、 適切な構文が見つかりません !
コトリンにはこのようなものがありますか?
var foo: Bar = Bar()
willSet() {
baz.prepareToDoTheThing()
}
didSet() {
baz.doTheThing()
}
Kotlinは、プロパティの変更を監視するための組み込みのSwiftスタイルのソリューションを提供していませんが、目的に応じていくつかの方法でそれを行うことができます。
observable(...)
デリゲート (stdlib) があり、プロパティの変更を処理できます。使用例:
_var foo: String by Delegates.observable("bar") { property, old, new ->
println("$property has changed from $old to $new")
}
_
ここで、_"bar"
_はプロパティfoo
の初期値であり、プロパティが割り当てられるたびにラムダが呼び出されるため、変更を観察できます。 vetoable(...)
デリゲート これにより、変更を防ぐことができます。
プロパティに custom setter を使用して、実際の値変更の前後に任意のコードを実行できます。
_var foo: String = "foo"
set(value: String) {
baz.prepareToDoTheThing()
field = value
baz.doTheThing()
}
_
@ KirillRakhman のように、このソリューションはメソッド呼び出しとオブジェクトにオーバーヘッドを導入しないため、非常に効率的です。ただし、いくつかのプロパティの場合、コードは少し重複します。
一般に、独自の プロパティデリゲート を実装して、getValue(...)
およびsetValue(...)
関数でプロパティの動作を明示的に提供できます。
タスクを簡素化するには、 _ObservableProperty<T>
_ 抽象クラスを使用します。これにより、プロパティの変更を監視するデリゲートを実装できます(上記のobservable
やvetoable
など)。例:
_var foo: String by object : ObservableProperty<String>("bar") {
override fun beforeChange(property: KProperty<*>, oldValue: String, newValue: String): Boolean {
baz.prepareToDoTheThing()
return true // return false if you don't want the change
}
override fun afterChange(property: KProperty<*>, oldValue: String, newValue: String) {
baz.doTheThing()
}
}
_
便宜上、デリゲートオブジェクトを作成する関数を作成できます。
_fun <T> observing(initialValue: T,
willSet: () -> Unit = { },
didSet: () -> Unit = { }
) = object : ObservableProperty<T>(initialValue) {
override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean =
true.apply { willSet() }
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = didSet()
}
_
次に、ラムダをwillSet
およびdidSet
( デフォルト引数 として_{ }
_)として渡します。使用法:
_var foo: String by observing("bar", willSet = {
baz.prepareToDoTheThing()
}, didSet = {
baz.doTheThing()
})
var baq: String by observing("bar", didSet = { println(baq) })
_
いずれにせよ、変更を監視するコードがプロパティを再度設定しないようにするのはあなた次第です。無限再帰に陥る可能性があります。そうでない場合は、監視するコードでセッターが再帰的に呼び出されるかどうかを確認します.