Kotlin 中有 didSet/willSet 类似物吗?
Is there a didSet/willSet analog in Kotlin?
我喜欢这种 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()
}
尽管 Kotlin 没有为 属性 变化观察提供内置的 Swift 风格的解决方案,您仍然可以根据您的目标以多种方式实现。
observable(...)
delegate (in stdlib) 允许您处理 属性 更改。使用示例:
var foo: String by Delegates.observable("bar") { property, old, new ->
println("$property has changed from $old to $new")
}
这里,"bar"
是属性的初始值foo
,每次赋值属性后都会调用lambda,允许您观察 changes.There 也允许您阻止更改的 vetoable(...)
delegate。
可以用custom setter换一个属性执行任意代码before/after实际值变化:
var foo: String = "foo"
set(value: String) {
baz.prepareToDoTheThing()
field = value
baz.doTheThing()
}
正如 @KirillRakhman 指出的那样,此解决方案非常有效,因为它不会在方法调用和对象中引入任何开销,尽管在多个属性的情况下代码会有点重复。
通常,您可以实现自己的 property delegate,在 getValue(...)
和 setValue(...)
函数中明确提供 属性 行为。
为了简化您的任务,使用 ObservableProperty<T>
抽象 class 允许您实现观察 属性 变化的委托(如上面的 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
传递给它(the default argument 对它们来说是 { }
)。用法:
var foo: String by observing("bar", willSet = {
baz.prepareToDoTheThing()
}, didSet = {
baz.doTheThing()
})
var baq: String by observing("bar", didSet = { println(baq) })
在任何情况下,由您来确保观察更改的代码不会再次设置 属性,因为它可能会陷入无限递归,否则您可以在观察代码是否递归调用 setter。
我喜欢这种 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()
}
尽管 Kotlin 没有为 属性 变化观察提供内置的 Swift 风格的解决方案,您仍然可以根据您的目标以多种方式实现。
observable(...)
delegate (in stdlib) 允许您处理 属性 更改。使用示例:var foo: String by Delegates.observable("bar") { property, old, new -> println("$property has changed from $old to $new") }
这里,
"bar"
是属性的初始值foo
,每次赋值属性后都会调用lambda,允许您观察 changes.There 也允许您阻止更改的vetoable(...)
delegate。可以用custom setter换一个属性执行任意代码before/after实际值变化:
var foo: String = "foo" set(value: String) { baz.prepareToDoTheThing() field = value baz.doTheThing() }
正如 @KirillRakhman 指出的那样,此解决方案非常有效,因为它不会在方法调用和对象中引入任何开销,尽管在多个属性的情况下代码会有点重复。
通常,您可以实现自己的 property delegate,在
getValue(...)
和setValue(...)
函数中明确提供 属性 行为。为了简化您的任务,使用
ObservableProperty<T>
抽象 class 允许您实现观察 属性 变化的委托(如上面的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
传递给它(the default argument 对它们来说是{ }
)。用法:var foo: String by observing("bar", willSet = { baz.prepareToDoTheThing() }, didSet = { baz.doTheThing() }) var baq: String by observing("bar", didSet = { println(baq) })
在任何情况下,由您来确保观察更改的代码不会再次设置 属性,因为它可能会陷入无限递归,否则您可以在观察代码是否递归调用 setter。