Kotlin-将infix函数移到其他函数中

时间:2018-11-25 09:28:13

标签: kotlin infix-notation

我使用属性可观察的委托。

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()
                  }

因此,我使用此infix函数来比较两个值。 但是,如果我想用它制作一个库,则需要将该infix函数移到某个地方,这样就不必每次都定义它了。但是我无法弄清楚方法,因为它取决于两个具体的值oldnew。所以我希望它看起来像这样:

var state: State by Delegates.observable(START as State,
          fun(prop: KProperty<*>, old: State, new: State) {
                  when {
                      START into STOP -> {
                          doSomeMagic()
                  }

然后在其他地方定义into

1 个答案:

答案 0 :(得分:2)

这是可能的,但是需要花费一些工作并在可观察的委托人的工作方式上进行一些结构性更改。

首先,创建一个类来保存更改的状态,这将使您也可以将infix函数添加到此类:

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类的扩展方法。因此,该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() }
            }
        }

现在在任何需要的地方使用它,您的infix函数将可用:

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主体包含所有推断出的内容。现在仍然没有参数。

这样做的代价是每次触发事件时都会重新分配小数据类。