Properties Kotlin中是否有didSet/willSet模拟?

Properties Kotlin中是否有didSet/willSet模拟?,properties,kotlin,didset,Properties,Kotlin,Didset,我喜欢这种快速的语法;这对很多事情都很有帮助: var foo: Bar = Bar() { willSet { baz.prepareToDoTheThing() } didSet { baz.doTheThing() } } 我很想在科特林做这件事。但是! 科特林有这样的东西吗? var foo: Bar = Bar() willSet() { baz.prepareToDoTheThing()

我喜欢这种快速的语法;这对很多事情都很有帮助:

var foo: Bar = Bar() {
    willSet {
        baz.prepareToDoTheThing()
    }
    didSet {
        baz.doTheThing()
    }
}
我很想在科特林做这件事。但是!

科特林有这样的东西吗?

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

尽管Kotlin没有为属性更改观察提供内置的Swift样式的解决方案,但根据您的目标,您仍然可以通过多种方式进行观察

  • 有一个委托允许您处理属性更改。用法示例:

    var foo: String by Delegates.observable("bar") { property, old, new ->
        println("$property has changed from $old to $new")
    }
    
    在这里,
    “bar”
    是属性
    foo
    的初始值,每次分配属性后都会调用lambda,允许您观察更改。还有一种方法允许您防止更改

  • 在实际值更改之前/之后,可以使用属性执行任意代码:

    var foo: String = "foo"
        set(value: String) {
            baz.prepareToDoTheThing()
            field = value
            baz.doTheThing()
        }
    
    如前所述,此解决方案非常有效,因为它不会在方法调用和对象中引入开销,尽管在有多个属性的情况下代码会有点重复

  • 通常,您可以实现自己的,在
    getValue(…)
    setValue(…)
    函数中显式提供属性行为

    为了简化任务,请使用允许您实现观察属性更改的委托的抽象类(如上面的
    observable
    vetoable
    ),例如:


在任何情况下,都由您来确保观察更改的代码不会再次设置属性,因为它可能会陷入无限递归,否则您可能会在观察代码中检查setter是否被递归调用。

令人惊讶的是,第二种方法正是我在提问和你回答之间建立的变通方法!:D@hotkey您应该详细介绍一下自定义setter,因为它是实现它的最有效的方法。@KirillRakhman,谢谢您的评论,我已经更新了答案。答案很好,但是IMO
true.apply{willSet()}
不是惯用的。我会用返回语句将其更改为代码块。@voddan,看起来Swift有
get
set
didSet
willSet
,Kotlin没有与
didSet
完全等价的东西(这就是问题所在)。
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()
 }
var foo: String by observing("bar", willSet = {
    baz.prepareToDoTheThing()
}, didSet = {
    baz.doTheThing()
})

var baq: String by observing("bar", didSet = { println(baq) })