Sup*_*tar 36 properties kotlin didset
我喜欢这个Swift语法; 它对很多东西很有帮助:
var foo: Bar = Bar() {
willSet {
baz.prepareToDoTheThing()
}
didSet {
baz.doTheThing()
}
}
Run Code Online (Sandbox Code Playgroud)
我很乐意在Kotlin这样做.但是,我找不到合适的语法!
Kotlin有什么相似的东西吗?
var foo: Bar = Bar()
willSet() {
baz.prepareToDoTheThing()
}
didSet() {
baz.doTheThing()
}
Run Code Online (Sandbox Code Playgroud)
hot*_*key 57
虽然Kotlin没有为属性变化观察提供内置的Swift风格解决方案,但您仍然可以通过多种方式来实现,具体取决于您的目标.
有observable(...)
委托(在stdlib中)允许您处理属性更改.用法示例:
var foo: String by Delegates.observable("bar") { property, old, new ->
println("$property has changed from $old to $new")
}
Run Code Online (Sandbox Code Playgroud)
这里"bar"
是property的初始值,foo
每次分配属性后都会调用lambda,允许您观察更改.还有vetoable(...)
委托可以阻止更改.
您可以使用属性的自定义setter在实际值更改之前/之后执行任意代码:
var foo: String = "foo"
set(value: String) {
baz.prepareToDoTheThing()
field = value
baz.doTheThing()
}
Run Code Online (Sandbox Code Playgroud)
正如@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()
}
}
Run Code Online (Sandbox Code Playgroud)
为方便起见,您可以编写一个创建委托对象的函数:
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()
}
Run Code Online (Sandbox Code Playgroud)
然后你只需通过lambda表达式把它当成willSet
和didSet
(默认参数对他们来说{ }
).用法:
var foo: String by observing("bar", willSet = {
baz.prepareToDoTheThing()
}, didSet = {
baz.doTheThing()
})
var baq: String by observing("bar", didSet = { println(baq) })
Run Code Online (Sandbox Code Playgroud)在任何情况下,它是由你来确保观察变化的代码不会再设置该属性,因为它很可能会陷入无限递归,否则你可能会检查它在观察代码的制定者是否被递归调用.