我想创建一个非空的某个类型的变量,例如Foo。
然后我希望对变量的所有访问都返回Foo,就像一个懒惰的委托一样,但是,我也希望能够重置它。
类似的东西:
var foo : String by Foo(init: {"bar"})
print(foo) // prints "bar"
foo = null // or foo.reset()
print(foo) // prints "bar"
我想解决的问题: 我有一个适配器的索引,我需要在适配器内容更改时重新创建。所以在改变时我想清除索引,下次有人试图访问它时,我想重新创建它。
答案 0 :(得分:7)
如果目标是让懒惰初始化var property
可以重置为初始状态,则可以调整Kotlin SynchronizedLazyImpl以允许无效< / em>功能:
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
}
}
然后可以按如下方式使用:
private val fooDelegate = InvalidatableLazyImpl({"bar"})
var foo:String by fooDelegate
println(foo); // -> "bar"
foo = "updated"
println(foo); // -> "updated"
fooDelegate.invalidate()
println(foo); // -> "bar"
显然可以修改委托实现以允许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`
答案 1 :(得分:1)
我有相同的要求,并编写了LazyEx
类,如下所示。
基于 miensol 的概念。 LazyEx
包装原始Kotlin的Lazy
属性,而不是对其进行改编。
fun <T> lazyEx(initializer: () -> T): LazyEx<T> = LazyEx(initializer)
class LazyEx<out T>(private var initializer: () -> T) : Lazy<T> {
@Volatile
private var wrap = Wrap()
override val value: T get() = wrap.lazy.value
override fun isInitialized() = wrap.lazy.isInitialized()
override fun toString() = wrap.lazy.toString()
fun invalidate() { wrap = Wrap() } // create a new Wrap object
private inner class Wrap { val lazy = lazy(initializer) }
}
用法:
object LazyExTest {
var i = 0
val fooDelegate = LazyEx { "bar${i++}" }
val foo by fooDelegate
fun run() {
println(foo) // -> "bar0"
println(fooDelegate.value) // -> "bar0"
fooDelegate.invalidate()
println(foo) // -> "bar1"
println(fooDelegate.value) // -> "bar1"
fooDelegate.invalidate()
println(fooDelegate.value) // -> "bar2"
}
}