11

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

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

编译器错误:

'this' is not defined in this context

我怎样才能将其限定为 Activity this?我已阅读指南,但无法获得。this@Activity表示参考未解决。

4

4 回答 4

9

这里的其他答案指出,不可能this在标准库的当前lazy接收器实现中进行引用,并且可以实现自己的委托。所以我决定实施它并将其发布在这里......:

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()}
    }
}

这是一些显示如何使用它的代码。

此实现使用弱哈希映射为每个接收者存储单独的值......这有几个含义......:

  • 结构上相同的不同实例将共享相同的值。

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

于 2016-06-28T19:39:13.350 回答
4

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

我看到两个解决方案:

  1. 将其转换为扩展功能
  2. 实现自己的委托
于 2015-12-21T10:24:01.770 回答
4

lazy第一次访问时调用initializer函数,然后存储返回的值,initializer以便在后续访问时返回该值。

的一个实例Lazy能够只存储一个值。当您将扩展属性委托给一个Lazy实例时,您将获得来自接收器类型的所有实例的Lazy服务getValue请求的单个实例,在您的情况下它是Activity. 这导致Lazy仅计算 firstActivity的值,并在所有后续调用Activity.

因此,尽管在语法上可以将Activity初始化器作为接收器传递并将其作为this内部引用,正如@voddan 在此答案中所建议的那样,但Lazy它本身无法为不同的接收器存储不同的值。

“附加属性”功能KT-7210可能涵盖了为扩展属性提供外部存储的能力。我认为不Lazy应该有这种能力,因为它的实现大大复杂化了。

于 2015-12-21T16:39:27.140 回答
1

我认为没有办法Activity从 的正文中访问lazy,至少使用当前的签名\实现:fun <T> lazy(initializer: () -> T): Lazy<T>

为此,签名必须看起来像

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

您可以自己实现这样的扩展功能,或者将其报告为 stdlib 的问题

于 2015-12-21T10:20:21.207 回答