2015-12-21 101 views
6

我想科特林并希望实施的活动一个懒惰的扩展属性此引用:在科特林扩展属性的懒惰初始化

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

编译器错误有:

'this' is not defined in this context 

哪有我认为这是“活动”吗?我已阅读a guide但无法获得。 [email protected]表示该参考文献尚未解决。

+0

你能显示更多的代码吗?使用此属性的类声明? –

+0

@EugeneKrivenja,这是一个顶级属性。打算在Activity子类方法中使用它来创建匕首模块。所以它是在一个单独的文件中定义的。像[那](https://github.com/Kotlin/anko/blob/a9109b510d362dbf133aa68d793fb1ebf1fdbd7b/dsl/static/src/common/Intents.kt) – Motorro

+0

另请参阅https://youtrack.jetbrains.com/issue/KT -13053有一个可能的解决方法 – Vadzim

回答

2

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

我看到了两个解决方案:

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

我觉得没有办法从lazy身体访问Activity,至少在目前的签名\执行:​​

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

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

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

+0

你会期望'T'类型的实例应该作为接收器传递给初始化器吗? – Ilya

+0

@Ilya我认为'thisRef as T'应该是接收者:https://kotlinlang.org/docs/reference/delegated-properties.html – voddan

+1

所以这个懒惰的实现将被限制为与接收者相同类型的returing值? – Ilya

3

lazy调用initializer功能,在访问第一次,然后存储在返回的值initializer在连续访问中返回该值。

Lazy的一个实例能够正好存储一个值。当您将扩展属性委托给Lazy实例时,您会收到一个Lazy实例,它将为来自接收器类型的所有实例的getValue请求提供服务,在您的案例中它的值为Activity。这导致Lazy计算值仅适用于第一个Activity,并将该值用于其他所有Activity实例的所有后续调用。

因此而它的语法能够传递一个Activity到初始化器作为接收器和作为@voddan在this answer建议参阅它作为this内部,Lazy本身不是能够存储不同的接收器不同的值的。

具有扩展属性的外部存储的功能很可能会被“附加属性”功能KT-7210覆盖。 我不认为Lazy应该有这个能力,因为它显着复杂化其实施。

+0

确实。没有正确的方法。只要顶层被静态解析 - 将只创建一个实例 – Motorro

2

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

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.

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

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

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