Я подал заявку на переназначение собственности делегата
internal object UNINITIALIZED_VALUE
class SynchronizedReassignableImpl<out T>(private val initializer: () -> T,
private val expiredPredicate: (T) -> Boolean,
lock: Any? = null) : Reassignable<T> {
@Volatile
private var _value: Any? = UNINITIALIZED_VALUE
private val lock = lock ?: this
override val value: T
get() {
if (!isExpired()) {
@Suppress("UNCHECKED_CAST") (_value as T)
}
return synchronized(lock) {
val _v2 = _value
@Suppress("UNCHECKED_CAST")
if (_v2 !== UNINITIALIZED_VALUE && !expiredPredicate.invoke(_value as T)) {
_v2 as T
} else {
val typedValue = initializer()
_value = typedValue
typedValue
}
}
}
@Suppress("UNCHECKED_CAST")
override fun isExpired(): Boolean = !isInitialized() || expiredPredicate.invoke(_value as T)
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Reassignable value not initialized yet."
operator fun getValue(any: Any, property: KProperty<*>): T = value
operator fun getValue(any: Nothing?, property: KProperty<*>): T = value
}
fun <T> reassignable(initializer: () -> T, expiredPredicate: (T) -> Boolean, lock: Any? = null): SynchronizedReassignableImpl<T> {
return SynchronizedReassignableImpl(initializer, expiredPredicate, lock)
}
interface Reassignable<out T> {
val value: T
fun isInitialized(): Boolean
fun isExpired(): Boolean
}
Этот код объявляет, что свойство Delegate работает как ленивый, но при каждом вызове получателя будет вызываться предикат для определения состояния значения (истек или нет). Если значение истекло, оно будет переназначено.
Работает, например
class SynchronizedReassignableImplTests {
@Test
fun isReassignable() {
val initializer = { mutableListOf<String>() }
val expiredPredicate = { l: List<String> -> l.size == 2 }
val list by reassignable(initializer, expiredPredicate)
Assertions.assertEquals(0, list.size)
list.add("item ${list.size}")
Assertions.assertEquals(1, list.size)
list.add("item ${list.size}") // list size is 2 on next getter's call it will be reassigned
Assertions.assertEquals(0, list.size)
list.add("item ${list.size}")
Assertions.assertEquals(1, list.size)
}
}
но я работаю с Kotlin всего два дня и думаю, что мое решение не очень красиво.
Может кто-нибудь дать мне совет, чтобы сделать это? А может, у Котлина есть нативное решение?