Kotlin - 将中缀函数从其他函数中移出
Kotlin - Move infix function inside other function out of it
我使用 属性 可观察委托。
var state: State by Delegates.observable(START as State,
fun(prop: KProperty<*>, old: State, new: State) {
infix fun State.into(s: State): Boolean {
return this == old && s == new
}
when {
START into STOP -> {
doSomeMagic()
}
所以,我使用这个中缀函数来比较两个值。
但是如果我想用它做一个库,我需要把这个中缀函数移到某个地方,这样就不需要每次都定义它了。但我想不出办法,因为它取决于两个具体值 old
和 new
。所以我希望它看起来像这样:
var state: State by Delegates.observable(START as State,
fun(prop: KProperty<*>, old: State, new: State) {
when {
START into STOP -> {
doSomeMagic()
}
并在其他地方定义 into
。
这是可能的,但需要做一些工作,并对可观察委托的工作方式进行一些结构更改。
首先,创建一个 class 来保持状态发生变化,这将允许您将中缀函数添加到此 class:
data class StateChange<T>(val property: KProperty<*>, val oldValue: T, val newValue: T) {
infix fun State.into(s: State): Boolean {
return this == oldValue && s == newValue
}
}
现在创建一个新的委托函数,它将创建委托而不是调用一个 lambda 函数,将所有值作为参数,将期望一个 lambda 是 StateChange
[=27 上的扩展方法=].因此,此 lambda 也可以访问其属性和函数。
inline fun <T> observableState(initialValue: T, crossinline onChange: StateChange<T>.() -> Unit):
ReadWriteProperty<Any?, T> =
object : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) {
with (StateChange(property, oldValue, newValue)) { onChange() }
}
}
现在你可以在任何地方使用它,你的中缀函数就可用了:
var state: State by observableState(START) {
// property, oldValue, and newValue are all here on this object!
when {
START into STOP -> { // works!
doSomeMagic(newValue) // example accessing the newValue
}
}
}
请注意,与将 lambda 函数传递给 observableState
函数时使用的语法略有不同,这更符合惯用的做法是不声明完整的函数头,而只包含推断出所有内容的 lambda 主体.现在反正没有参数了。
这样做的成本是每次触发事件时新分配的小数据class。
我使用 属性 可观察委托。
var state: State by Delegates.observable(START as State,
fun(prop: KProperty<*>, old: State, new: State) {
infix fun State.into(s: State): Boolean {
return this == old && s == new
}
when {
START into STOP -> {
doSomeMagic()
}
所以,我使用这个中缀函数来比较两个值。
但是如果我想用它做一个库,我需要把这个中缀函数移到某个地方,这样就不需要每次都定义它了。但我想不出办法,因为它取决于两个具体值 old
和 new
。所以我希望它看起来像这样:
var state: State by Delegates.observable(START as State,
fun(prop: KProperty<*>, old: State, new: State) {
when {
START into STOP -> {
doSomeMagic()
}
并在其他地方定义 into
。
这是可能的,但需要做一些工作,并对可观察委托的工作方式进行一些结构更改。
首先,创建一个 class 来保持状态发生变化,这将允许您将中缀函数添加到此 class:
data class StateChange<T>(val property: KProperty<*>, val oldValue: T, val newValue: T) {
infix fun State.into(s: State): Boolean {
return this == oldValue && s == newValue
}
}
现在创建一个新的委托函数,它将创建委托而不是调用一个 lambda 函数,将所有值作为参数,将期望一个 lambda 是 StateChange
[=27 上的扩展方法=].因此,此 lambda 也可以访问其属性和函数。
inline fun <T> observableState(initialValue: T, crossinline onChange: StateChange<T>.() -> Unit):
ReadWriteProperty<Any?, T> =
object : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) {
with (StateChange(property, oldValue, newValue)) { onChange() }
}
}
现在你可以在任何地方使用它,你的中缀函数就可用了:
var state: State by observableState(START) {
// property, oldValue, and newValue are all here on this object!
when {
START into STOP -> { // works!
doSomeMagic(newValue) // example accessing the newValue
}
}
}
请注意,与将 lambda 函数传递给 observableState
函数时使用的语法略有不同,这更符合惯用的做法是不声明完整的函数头,而只包含推断出所有内容的 lambda 主体.现在反正没有参数了。
这样做的成本是每次触发事件时新分配的小数据class。