Kotlin lazy default свойство

В Kotlin, как я могу определить var который имеет ленивое значение по умолчанию?

например, значение val будет примерно таким:

val toolbarColor  by lazy {color(R.color.colorPrimary)}

То, что я хочу сделать, имеет значение по умолчанию для некоторого свойства (toolbarColor), и я могу изменить это значение для чего-либо еще. Является ли это возможным?

EDIT: Это делает частичный трюк.

var toolbarColor = R.color.colorPrimary
    get() = color(field)
    set(value){
        field = value
    }

Можно ли это облегчить, написав

var toolbarColor = color(R.color.colorPrimary)
    set(value){
        field = value
    }

таким образом, что значение по умолчанию вычисляется лениво? На данный момент это не сработает, потому что color() нуждается в Context который только инициализируется позже.

Ответ 1

Вы можете создать свой собственный метод делегирования:

private class ColorDelegate<T>(initializer: () -> T) : ReadWriteProperty<Any?, T> {

    private var initializer: (() -> T)? = initializer

    private var value: T? = null

    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value ?: initializer!!()
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }
}

Объявить в некоторых делегатах:

object DelegatesExt {
    fun <T> lazyColor(initializer: () -> T): ReadWriteProperty<Any?, T> = ColorDelegate(initializer)
}

И используйте следующее:

var toolbarColor by DelegatesExt.lazyColor {
    // you can have access to your current context here.
    // return the default color to be used
    resources.getColor(R.color.your_color)
}

...

override fun onCreate(savedInstanceState: Bundle?) {
    // some fun code
    // toolbarColor at this point will be R.color.your_color
    // but you can set it a new value
    toolbarColor = resources.getColor(R.color.new_color)
    // now toolbarColor has the new value that you provide.
}

Я думаю, что это может быть более чистый способ сделать, но я еще не знаю (начиная с kotlin несколько дней назад). Я посмотрю, посмотрим, можно ли это сделать с меньшим количеством кода.

Ответ 2

Вы можете сохранить свою собственность на карте, чтобы в принципе создать изменчивый ленивый. Вам нужна изменчивая карта (например, HashMap<K, V>) с функцией по умолчанию для делегирования:

var toolbarColor by hashMapOf<String, Any?>()
        .withDefault { toolbarColor = R.color.colorPrimary; toolbarColor }

Вам также потребуется импортировать некоторые функции расширения: import kotlin.properties.getValue и import kotlin.properties.setValue.

Было бы неплохо, если бы Котлин предоставил что-то встроенное и оптимизированное для этого (например, mutableLazy или что-то еще). Таким образом, я создал KT-10451.