Kotlin - убрать инфиксную функцию из другой функции из нее - PullRequest
0 голосов
/ 25 ноября 2018

Я использую делегат с наблюдаемым свойством.

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 где-то еще.

1 Ответ

0 голосов
/ 25 ноября 2018

Это возможно, но требует небольшой работы и небольшого структурного изменения в том, как работает наблюдаемый делегат.

Сначала создайте класс для хранения состояния при изменении, это позволит вам также добавить в этот класс свою инфиксную функцию:

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

Теперь создайте новую функцию-делегат, которая будетсоздайте делегат и вместо вызова лямбда-функции со всеми значениями в качестве параметра будет ожидать лямбда, являющуюся методом расширения класса StateChange.Поэтому эта лямбда также будет иметь доступ к своим свойствам и функциям.

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

Обратите внимание на немного другоеСинтаксис, который вы используете для передачи лямбда-функции в функцию observableState, более идиоматичен, чтобы не объявлять полный заголовок функции, а вместо этого просто иметь лямбда-тело со всем выводом.Теперь все равно нет параметров.

Стоимость этого - новое выделение небольшого класса данных каждый раз, когда происходит событие.

...