Kotlin 属性 委托未按预期工作
Kotlin property delegation not working as expected
我对使用 getter 还是委托属性的不同行为感到困惑。考虑以下因素:
class Test {
class Parts(val a: String, val b: String)
var raw = ""
private var cachedParts: Parts? = null
val parts: Parts
get() {
println("@2")
return cachedParts
?: raw.split("/")
.let { Parts(it.getOrElse(0) { "" }, it.getOrElse(1) { "" }) }
.also { cachedParts = it }
}
// WITH GETTERS:
val partA get() = parts.a
val partB get() = parts.b
}
fun main() {
val t = Test()
println("@1")
t.raw = "one/two"
println("a=${t.partA}, b=${t.partB}")
}
此代码在第一次访问 parts
时将字符串 raw
分成两部分。所有以后对 parts
的调用都将 return 缓存的部分,即使 raw
发生变化。输出:
@1
@2
@2
a=one, b=two
创建 Test
时 raw
的值为空,但在我们将 raw
设置为某个字符串之前不会调用访问器。当最终访问 partA
和 partB
时,它们包含正确的值。
如果我改用 属性 委派,代码将不再有效:
class Test {
class Parts(val a: String, val b: String)
var raw = ""
private var cachedParts: Parts? = null
val parts: Parts
get() {
println("@2")
return cachedParts
?: raw.split("/")
.let { Parts(it.getOrElse(0) { "" }, it.getOrElse(1) { "" }) }
.also { cachedParts = it }
}
// WITH DELEGATION:
val partA by parts::a
val partB by parts::b
}
fun main() {
val t = Test()
println("@1")
t.raw = "one/two"
println("a=${t.partA}, b=${t.partB}")
}
我在这里所做的所有更改是 partA
现在委托给 parts::a
,partB
也是如此。由于某些奇怪的原因,partA
和 partB
现在被访问 在 设置 raw
的值之前,因此 cachedParts
被初始化为两个空的部分。输出:
@2
@2
@1
a=, b=
谁能解释一下这是怎么回事?
在文档 here 中查看您的委托属性转换成什么。例如,partA
转换为:
private val partADelegate = parts::a
val partA: String
get() = partADelegate.getValue(this, this::partA)
注意可调用引用表达式part::a
用于初始化partADelegate
。在创建 Test
的实例时,在 println("@1")
.
之前计算此表达式
要计算 parts::a
,必须先计算 parts
。毕竟这是对parts
a
属性的引用,而不是对parts
.
的引用
因此,parts
最终在 raw
获得其值之前被评估。
我对使用 getter 还是委托属性的不同行为感到困惑。考虑以下因素:
class Test {
class Parts(val a: String, val b: String)
var raw = ""
private var cachedParts: Parts? = null
val parts: Parts
get() {
println("@2")
return cachedParts
?: raw.split("/")
.let { Parts(it.getOrElse(0) { "" }, it.getOrElse(1) { "" }) }
.also { cachedParts = it }
}
// WITH GETTERS:
val partA get() = parts.a
val partB get() = parts.b
}
fun main() {
val t = Test()
println("@1")
t.raw = "one/two"
println("a=${t.partA}, b=${t.partB}")
}
此代码在第一次访问 parts
时将字符串 raw
分成两部分。所有以后对 parts
的调用都将 return 缓存的部分,即使 raw
发生变化。输出:
@1
@2
@2
a=one, b=two
创建 Test
时 raw
的值为空,但在我们将 raw
设置为某个字符串之前不会调用访问器。当最终访问 partA
和 partB
时,它们包含正确的值。
如果我改用 属性 委派,代码将不再有效:
class Test {
class Parts(val a: String, val b: String)
var raw = ""
private var cachedParts: Parts? = null
val parts: Parts
get() {
println("@2")
return cachedParts
?: raw.split("/")
.let { Parts(it.getOrElse(0) { "" }, it.getOrElse(1) { "" }) }
.also { cachedParts = it }
}
// WITH DELEGATION:
val partA by parts::a
val partB by parts::b
}
fun main() {
val t = Test()
println("@1")
t.raw = "one/two"
println("a=${t.partA}, b=${t.partB}")
}
我在这里所做的所有更改是 partA
现在委托给 parts::a
,partB
也是如此。由于某些奇怪的原因,partA
和 partB
现在被访问 在 设置 raw
的值之前,因此 cachedParts
被初始化为两个空的部分。输出:
@2
@2
@1
a=, b=
谁能解释一下这是怎么回事?
在文档 here 中查看您的委托属性转换成什么。例如,partA
转换为:
private val partADelegate = parts::a
val partA: String
get() = partADelegate.getValue(this, this::partA)
注意可调用引用表达式part::a
用于初始化partADelegate
。在创建 Test
的实例时,在 println("@1")
.
要计算 parts::a
,必须先计算 parts
。毕竟这是对parts
a
属性的引用,而不是对parts
.
因此,parts
最终在 raw
获得其值之前被评估。