为什么 Kotlin 允许在没有支持字段的情况下委托扩展属性?

问题描述 投票:0回答:1

我明白为什么 Kotlin 不允许初始化扩展属性,例如

val SomeClass.anExtensionProperty = "can't do this"

因为没有支持字段来保存该值。我知道你可以使用

get()
'ter 因为它不保存状态,如下所示:

val SomeClass.anExtensionProperty get() = "you CAN do this"

因为它是动态计算的并且没有状态可以保存。

所以我很惊讶地发现你可以做到这一点:

val SomeClass.anExtentionsionProperty by lazy{
   "you CAN do this, but why?"
}

在我看来,当正常使用

by
委托(不使用扩展)时,您正在“设置”一个属性来引用委托,这意味着存储对实例化对象的引用(即状态)。这似乎违反了对扩展属性的限制。

为什么允许这样做?幕后发生了什么?

kotlin delegates extension-methods
1个回答
0
投票

当我们使用

by
运算符时,编译器会计算右侧的值并将委托存储在当前作用域中。如果我们在函数中执行此操作,委托将存储为局部变量。如果我们在班级中,则将其存储为成员。如果我们位于顶级范围内,则它存储在顶级范围中。

您的案例是最后一个。我们位于顶级范围内,因此我们在顶级范围内创建一个委托。它不会为每个实例创建单独的惰性对象。它创建一个全局实例并在所有实例之间共享它。我们可以很容易地验证这一点:

fun main() {
    val c1 = SomeClass()
    println(c1.anExtentionsionProperty)
    val c2 = SomeClass()
    println(c2.anExtentionsionProperty)
}

class SomeClass

val SomeClass.anExtentionsionProperty by lazy{
    println("hello")
    "you CAN do this, but why?"
}

此代码仅打印一次“hello”,因为两个实例共享相同的惰性。

我们也可以在字节码中验证这一点:

public final class Test1Kt {
  private final static Lkotlin/Lazy; anExtentionsionProperty$delegate
}

它在

Test1Kt
类中创建了一个静态字段(文件名为
test1.kt
),并在那里存储了
Lazy
对象。然后它在
getAnExtentionsionProperty
方法中访问它。

© www.soinside.com 2019 - 2024. All rights reserved.