web-dev-qa-db-ja.com

KotlinにはdidSet / willSetアナログがありますか?

私はこれが大好きですSwift構文;それは多くのことに非常に役立ちます:

var foo: Bar = Bar() {
    willSet {
        baz.prepareToDoTheThing()
    }
    didSet {
        baz.doTheThing()
    }
}

これをコトリンでやりたいです。ただし、 適切な構文が見つかりません

コトリンにはこのようなものがありますか?

var foo: Bar = Bar()
    willSet() {
        baz.prepareToDoTheThing()
    }
    didSet() {
        baz.doTheThing()
    }
33
Supuhstar

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>_ 抽象クラスを使用します。これにより、プロパティの変更を監視するデリゲートを実装できます(上記のobservablevetoableなど)。例:

    _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) })
    _

いずれにせよ、変更を監視するコードがプロパティを再度設定しないようにするのはあなた次第です。無限再帰に陥る可能性があります。そうでない場合は、監視するコードでセッターが再帰的に呼び出されるかどうかを確認します.

51
hotkey