11

Kotlin を試していて、Activity の遅延拡張プロパティを実装したいと考えています。

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

コンパイラ エラー:

'this' is not defined in this context

これをアクティビティとして認定するにはどうすればよいですか? ガイドを読みましたが、入手できません。this@Activity参照が未解決であると言います。

4

4 に答える 4

9

thisここでの他の回答は、stdlib の現在のレシーバーの実装内で参照することは不可能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デリゲートには、プロパティ メンバー クラスへの参照がありません。

2 つの解決策があります。

  1. それを拡張関数に変換します
  2. 独自のデリゲートを実装する
于 2015-12-21T10:24:01.770 に答える
4

lazyinitializer初めてアクセスされたときに function を呼び出し、 によって返された値を格納してinitializer、後続のアクセスでその値を返します。

のインスタンスはLazy、正確に 1 つの値を格納できます。拡張プロパティをインスタンスに委譲すると、レシーバー タイプのすべてのインスタンスからリクエストを処理Lazyする単一のインスタンスが取得されます。この場合は. これにより、最初の値のみが計算され、 の他のインスタンスに対する後続のすべての呼び出しでその値が使用されます。LazygetValueActivityLazyActivityActivity

したがって、@voddan がこの回答Activityで示唆しているように、 to イニシャライザをレシーバとして渡し、それを内部として参照することは構文的に可能ですが、それ自体は異なるレシーバに対して異なる値を格納することはできません。thisLazy

拡張プロパティ用の外部ストレージを持つ機能は、「添付プロパティ」機能KT-7210でカバーされる可能性があります。Lazy実装が非常に複雑になるため、この機能を持つべきではないと思います。

于 2015-12-21T16:39:27.140 に答える