0

我实施了 Reassignable Property Delegate

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 属性像惰性一样工作,但在每次 getter 调用时,都会调用谓词来定义值状态(是否过期)。如果该值过期,则将重新分配该值。

例如,它正在工作

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 两天,并认为我的解决方案不是那么漂亮。有人可以给我建议吗?或者也许 Kotlin 有一个原生的解决方案?

4

0 回答 0