我喜欢这个Swift语法;这对很多事情都非常有帮助:
var foo: Bar = Bar() {
willSet {
baz.prepareToDoTheThing()
}
didSet {
baz.doTheThing()
}
}
我很乐意在Kotlin这样做。但是,I can't find the proper syntax!
Kotlin有这样的东西吗?
var foo: Bar = Bar()
willSet() {
baz.prepareToDoTheThing()
}
didSet() {
baz.doTheThing()
}
答案 0 :(得分:46)
虽然Kotlin没有为属性变化观察提供内置的Swift风格解决方案,但您仍可以通过多种方式实现,具体取决于您的目标。
observable(...)
委托(in stdlib)允许您处理属性更改。用法示例:
var foo: String by Delegates.observable("bar") { property, old, new ->
println("$property has changed from $old to $new")
}
这里,"bar"
是属性foo
的初始值,每次分配属性后都会调用lambda,允许您观察更改。还有{{3允许你阻止改变。
您可以使用vetoable(...)
delegate属性在实际值更改之前/之后执行任意代码:
var foo: String = "foo"
set(value: String) {
baz.prepareToDoTheThing()
field = value
baz.doTheThing()
}
正如custom setter所指出的,这个解决方案非常有效,因为它在方法调用和对象中没有引入任何开销,尽管在多个属性的情况下代码会有点重复。
通常,您可以实现自己的@KirillRakhman,在getValue(...)
和setValue(...)
函数中明确提供属性行为。
为了简化您的任务,请使用property delegate抽象类,它允许您实现观察属性更改的委托(例如上面的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()
}
然后你只需将lambdas传递给它willSet
和didSet
(ObservableProperty<T>
为{ }
)。用法:
var foo: String by observing("bar", willSet = {
baz.prepareToDoTheThing()
}, didSet = {
baz.doTheThing()
})
var baq: String by observing("bar", didSet = { println(baq) })
在任何情况下,由您来确保观察更改的代码不会再次设置属性,因为它可能会进入无限递归,否则您可能会在观察代码中检查它是否是setter是递归地叫。