具有重置的惰性变量

Hei*_*sch 6 kotlin

我想创建一个非空的特定类型的变量,例如Foo.

然后我希望对变量的所有访问都返回Foo,就像一个惰性委托一样,但是,我也希望能够重置它.

就像是:

var foo : String by Foo(init: {"bar"})

print(foo) // prints "bar"
foo = null // or foo.reset()
print(foo) // prints "bar"
Run Code Online (Sandbox Code Playgroud)

我试图解决的问题:我有一个适配器的索引,我需要在适配器内容更改时重新创建.所以在改变时我想清除索引,下次有人试图访问它时,我想重新创建它.

mie*_*sol 7

如果目标是进行延迟初始化var property,可以将其重置为初始状态,则可以调整Kotlin的SynchronizedLazyImpl以允许无效功能:

private object UNINITIALIZED_VALUE
class InvalidatableLazyImpl<T>(private val initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
    @Volatile private var _value: Any? = UNINITIALIZED_VALUE
    private val lock = lock ?: this
    fun invalidate(){
        _value = UNINITIALIZED_VALUE
    }

    override val value: T
        get() {
            val _v1 = _value
            if (_v1 !== UNINITIALIZED_VALUE) {
                return _v1 as T
            }

            return synchronized(lock) {
                val _v2 = _value
                if (_v2 !== UNINITIALIZED_VALUE) {
                    _v2 as T
                }
                else {
                    val typedValue = initializer()
                    _value = typedValue
                    typedValue
                }
            }
        }


    override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE

    override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."

    operator fun setValue(any: Any, property: KProperty<*>, t: T) {
        _value = t
    }
}
Run Code Online (Sandbox Code Playgroud)

然后可以使用如下:

private val fooDelegate = InvalidatableLazyImpl({"bar"})
var foo:String by fooDelegate

println(foo); // -> "bar"
foo = "updated"
println(foo); // -> "updated"
fooDelegate.invalidate()
println(foo); // -> "bar"
Run Code Online (Sandbox Code Playgroud)

显然,可以修改委托实现以允许null值作为重置,但是它可能使代码更难以推理,即:

println(obj.foo); //-> prints "bar
obj.foo = null //reset the value, implicitely
println(obj.foo); //-> prints "bar", but hey didn't I just said `null`
Run Code Online (Sandbox Code Playgroud)

  • 好的解决方案 同意`foo = null`很难推理.作为一个次要的建议,我建议其他读者,我建议将`reset`方法重命名为`invalidate`,因为那是你真正做的 - 使缓存的值无效. (2认同)