Kotlin中是否有一个didSet / willSet类似物?
我喜欢这个Swift语法; 这对许多事情非常有帮助:
var foo: Bar = Bar() { willSet { baz.prepareToDoTheThing() } didSet { baz.doTheThing() } }
我很想在Kotlin做这个。 但是, 我找不到合适的语法 !
Kotlin有这样的东西吗?
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
的初始值,lambda在属性被赋值后每次被调用,允许你观察变化。还有可vetoable(...)
委托 ,可以让你阻止变更。 -
您可以使用自定义设置器来执行实际值更改之前/之后的任意代码:
var foo: String = "foo" set(value: String) { baz.prepareToDoTheThing() field = value baz.doTheThing() }
正如@KirillRakhman指出的那样,这个解决方案非常有效,因为它不会在方法调用和对象中引入任何开销,但是在多个属性的情况下代码将会被重复一些。
-
通常,您可以实现自己的属性委托 ,在
getValue(...)
和setValue(...)
函数中显式提供属性行为。为了简化您的任务,使用
ObservableProperty<T>
抽象类,允许您实现观察属性更改的vetoable
(如上面的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() }
然后,您只需将lambda传递给它,因为
willSet
和didSet
(它们的默认参数是{ }
)。 用法:var foo: String by observing("bar", willSet = { baz.prepareToDoTheThing() }, didSet = { baz.doTheThing() }) var baq: String by observing("bar", didSet = { println(baq) })
在任何情况下,您都应该确保观察更改的代码不会再次设置属性,因为它可能属于无限递归,否则您可以在观察代码中检查是否递归调用setter。