I love this Swift syntax; it's very helpful for many things:

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

and I'd love to do this in Kotlin. However, I can't find the proper syntax!

Is there anything in Kotlin like this?

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

推荐答案

Although Kotlin doesn't provide a built-in Swift-style solution for property changes observation, you can still do it in several ways depending on what your goal is.

  • observable(...)个委托(in stdlib)允许您处理属性更改.使用示例:

    var foo: String by Delegates.observable("bar") { property, old, new ->
        println("$property has changed from $old to $new")
    }
    

    这里,"bar"是属性foo的初始值,每次分配属性后都会调用lambda,以便观察更改.还有vetoable(...) delegate种方法可以防止这种变化

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

    var foo: String = "foo"
        set(value: String) {
            baz.prepareToDoTheThing()
            field = value
            baz.doTheThing()
        }
    

    @KirillRakhman所述,此解决方案非常有效,因为它不会在方法调用和对象中引入任何开销,尽管在有几个属性的情况下代码会有点重复.

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

    To simplify your task, use ObservableProperty<T> abstract class that allows you to implement delegates that observe property changes (like observable and vetoable above) Example:

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

    然后把lambdas作为willSetdidSet传递给它(the default argument代表{ }).用法:

    var foo: String by observing("bar", willSet = {
        baz.prepareToDoTheThing()
    }, didSet = {
        baz.doTheThing()
    })
    
    var baq: String by observing("bar", didSet = { println(baq) })
    

In any case, it's up to you to make sure that the code observing the changes doesn't set the property again as it will likely fall into infinite recursion, or else you might check it in the observing code whether the setter is called recursively.

Kotlin相关问答推荐

在没有外部 map 的情况下转换列表项

这些Kotlin函数等效吗?

带有Spring Boot和Kotline的可嵌入实体

Android Jetpack编写androidx.compose.oundation.lazy.grid.Items

合并状态流

有没有办法在 jetpack compose 中将 TextField 密码点图标增加得更大?

始终抛出的函数 - 具有块主体的函数中需要的返回表达式

kotlin 父类具有依赖于抽象变量的变量

jlink:在合并模块和 kotlin.stdlib 中打包 kotlin.*

为什么 Kotlin 中的 Double 和 Long 类型不推荐直接转换为 Char?

在 kotlin 中重载函数时,我在一些非常基本的代码上不断收到类型不匹配

创建首选项屏幕时找不到androidx.preference.PreferenceScreen

androidx.core:core-ktx:1.0.0 小部件包丢失

哪里可以找到aapt2日志(log)?

为什么 Kotlin Pair 中的条目不可变?

如何在 Kotlin 中传递有界通配符类型参数?

在调用Kotlin数据类中的超类构造函数之前访问函数

用mockk验证属性设置程序吗?

Kotlin lambda 语法混淆

Kotlin中对象和数据类的区别是什么?