2015-12-21 99 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的實例將共享相同的值。

  • 在某些情況下,某些接收方已初始化的值可能被垃圾收集,這意味着如果再次訪問該值,可能會再次調用初始值設定項以重新初始化該值。