我对数据类做了一个var扩展属性,如下所示:
var Element.bitmap: Bitmap?
get() = downloadImg(PLACE_HOLDER_URL) //Default
set(value) = this.bitmap.let {
it = value ?: return@let
}
但是,当我尝试在此行中将“ it”重新分配给新值时,编译器抱怨“ Val无法重新分配”:
it = value ?: return@let
我真不明白为什么会这样??我有一个“ var”位图属性,而不是“ val”,那是什么问题?更重要的是什么是解决方案或替代方案?
答案 0 :(得分:2)
lambda内部的变量是不可变的,it
有变量bitmap
的浅表副本。
您应该使用field
分配到后备字段(实际变量)。
set(value) {
value?.let { field = it }
}
let
函数创建变量的浅表副本,因此,如果另一个线程更改了可见的可变变量(var),则可以安全地使用它,而不会冒突变的危险。
示例:
class Test {
var prop: Int? = 5
}
fun main() {
val test = Test()
thread {
Thread.sleep(100)
test.prop = null
}
if (test.prop != null) {
Thread.sleep(300) // pretend we did something
println(test.prop) // prints null even inside if check
}
}
为解决这些情况,使用了浅拷贝,例如let
,它传递了这些不变的浅拷贝。
class Test {
var prop: Int? = 5
}
fun main() {
val test = Test()
thread {
Thread.sleep(100)
test.prop = null
}
test.prop?.let { // `it` is a shallow copy, changes won't be reflected
Thread.sleep(300) // pretend we did something
println(it) // prints 5
}
}
结论:it
本身并不是实际变量,因此即使您能够为it
分配某些内容,更改也不会反映到实际变量中。
编辑:扩展程序属性没有后备字段,扩展程序实际上是获取器和设置器。
委托示例:
class ElementBitmapDelegate {
private var value: Bitmap? = null
operator fun getValue(thisRef: Any?, property: KProperty<*>): Bitmap {
return value ?: downloadImg(PLACE_HOLDER_URL).also { setValue(thisRef, property, it) }
// return value or if value is null return from downloadImg() and set it to value
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, v: Bitmap?) {
v?.let { value = it } // if v is not null then set value to v
}
}
var Element.bitmap: Bitmap? by ElementBitmapDelegate()
答案 1 :(得分:0)
要创建自定义设置器,您需要通过field
而不是it
访问property的后备字段,如下所示:
set(value) = {
field = value
}