kotlin 扩展 属性 的延迟初始化程序中的此引用

this reference in a lazy initializer of kotlin extension property

我正在尝试使用 Kotlin 并想为 Activity 实现惰性扩展 属性:

/**
 * Activity module
 */
val Activity.activityModule: ActivityModule by lazy {
    ActivityModule(this)
}

编译器错误:

'this' is not defined in this context

我怎样才能将其定义为Activity?我已阅读 a guide 但无法阅读。 this@Activity 表示引用未解决。

我认为无法从 lazy 的主体访问 Activity,至少对于当前的 signature\implementation:fun <T> lazy(initializer: () -> T): Lazy<T>

要做到这一点,签名必须看起来像

fun <A, T> lazy(initializer: A.() -> T): Lazy2<A, T>

您可以自己实现这样的扩展功能,or\and将此报告为 stdlib 的问题

Kotlin 中的 lazy 委托没有引用 属性 成员 class。

我看到两个解决方案:

  1. 将其转换为扩展函数
  2. 实现自己的委托

lazy 在第一次访问时调用 initializer 函数,然后将 return 由 initializer 编辑的值存储到 return 该值连续访问。

Lazy 的实例只能存储一个值。当您将扩展名 属性 委托给 Lazy 实例时,您将获得 Lazy 的单个实例,为来自接收方类型的所有实例的 getValue 请求提供服务,在您的情况下是Activity。这导致 Lazy 仅计算第一个 Activity 的值,并在 Activity.

的其他实例的所有后续调用中使用该值

因此,虽然在语法上可以将 Activity 作为接收者传递给初始化程序,并将其作为 this 在内部引用,正如@voddan 在 中所建议的那样,Lazy本身不能为不同的接收者存储不同的值。

"Attached properties" 功能 KT-7210 可能涵盖为扩展属性提供外部存储的能力。 我认为 Lazy 不应该具有这种能力,因为它会使实施变得非常复杂。

这里的其他答案指出,不可能在 stdlib 当前实现的 lazy 接收器中引用 this,并且可以实现他们自己的委托。所以我决定在这里实施它并 post 它...:[=​​15=]

class LazyWithReceiver<This,Return>(val initializer:This.()->Return)
{
    private val values = WeakHashMap<This,Return>()

    @Suppress("UNCHECKED_CAST")
    operator fun getValue(thisRef:Any,property:KProperty<*>):Return = synchronized(values)
    {
        thisRef as This
        return values.getOrPut(thisRef) {thisRef.initializer()}
    }
}

Here is some code showing how to use it.

此实现使用弱散列映射为每个接收者存储单独的值...这带来了一些影响...:[=​​15=]

  • structurally equal 的不同实例将共享相同的值。

  • 在某些情况下,已经为某些接收器初始化的值可能会被垃圾收集,这意味着如果再次访问初始化程序可能会再次调用以重新初始化该值。