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

创建 Testraw 的值为空,但在我们将 raw 设置为某个字符串之前不会调用访问器。当最终访问 partApartB 时,它们包含正确的值。

如果我改用 属性 委派,代码将不再有效:

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::apartB 也是如此。由于某些奇怪的原因,partApartB 现在被访问 设置 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。毕竟这是对partsa属性的引用,而不是对parts.

的引用

因此,parts 最终在 raw 获得其值之前被评估。