Знакомство с Kotlin делегатами - PullRequest
0 голосов
/ 13 марта 2020

Я изо всех сил пытаюсь обернуть голову вокруг Kotlin делегатов. Я нахожу это особенно хитрым, когда дело доходит до использования его с generics . В моем случае я хочу делегата, где я могу хранить значение произвольного типа. При первом обращении к делегированному свойству оно возвращает сохраненное значение. Все последующие обращения просто возвращают null. Если я снова установлю значение, то следующий доступ вернет значение, и все последующие операции доступа снова вернут null. Это будет работать так:

val a: Int by AccessOnce() // or String, or Boolean, or whatever
println(a) // null
a = 42
println(a) // 42
println(a) // null

a = 100
println(a) // 100
println(a) // null

Это код, который у меня есть, но он недоволен сигнатурами getValue и setValue. Не могли бы вы помочь мне?

import kotlin.reflect.KProperty

class AccessOnce <T> {
    var storedValue: T? = null
    operator fun getValue(thisRef: T?, property: KProperty<*>): T? {
        val retVal =  storedValue
        storedValue = null
        return retVal
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
        storedValue = value
    }

}

1 Ответ

0 голосов
/ 13 марта 2020

Проблема с вашим кодом заключается в том, что вы объединяете типы thisRef и самого свойства. thisRef - это любой объект, имеющий свойство, которое делегируется. В большинстве случаев вы просто сделаете его типа Any, чтобы ваш делегат мог использоваться в любом классе, который вам нравится. Но если у вас был специальный тип делегата, который работает только для определенного типа класса, вы могли бы использовать этот тип для thisRef, а затем в операторных функциях вы могли бы, чтобы ваш получатель и / или установщик вызывал другие функции класса или делать другую работу.

Так что, чтобы исправить вашу, вам просто нужно изменить thisRef на Any.

class AccessOnce <T> {
    var storedValue: T? = null
    operator fun getValue(thisRef: Any, property: KProperty<*>): T? {
        val retVal =  storedValue
        storedValue = null
        return retVal
    }

    operator fun setValue(thisRef: Any, property: KProperty<*>, value: T?) {
        storedValue = value
    }

}

Кстати, getValue может быть однострочным:

    operator fun getValue(thisRef: Any, property: KProperty<*>): T? =
         storedValue.also { storedValue = null }
...