2016-01-30 10 views
8

私はハックを別の答えquestionに一般化しようとしています。イニシャライザで自己参照を提供するKotlinのutil関数を書く

初期化子の内部ではまだ構築されていない値を参照する方法を提供するはずです(もちろん、直接ではなく、ラムダとオブジェクト式で)。

私が現時点で持っている:

class SelfReference<T>(val initializer: SelfReference<T>.() -> T) { 
    val self: T by lazy { 
     inner ?: throw IllegalStateException("Do not use `self` until initialized.") 
    } 

    private val inner = initializer() 
} 

fun <T> selfReference(initializer: SelfReference<T>.() -> T): T { 
    return SelfReference(initializer).self 
} 

それは動作しますが、この例を参照してください。

class Holder(var x: Int = 0, 
      val action:() -> Unit) 

val h: Holder = selfReference { Holder(0) { self.x++ } } 
h.action() 
h.action() 
println(h.x) //2 

しかし、この時点でinitializerが構築された値を参照する方法はselfプロパティです。

私の質問は、initializerselfプロパティを使用する代わりに引数(または受信者)が渡されるようにSelfReferenceを書き換える方法はありますか?この質問は、遅延評価された受信側/引数を関数に渡すか、このセマンティクスを何らかの方法で達成する方法があるか、

コードを改善する他の方法は何ですか?


UPD:可能な方法の1つは、 selfを返す関数を渡すことです。したがって、 initializerの内部に it()として使用されます。まだ他のものを探しています。

+1

[委任されたプロパティ](https://kotlinlang.org/docs/reference/delegated-properties.html#delegated-properties)、[late-initialized properties](https: /kotlinlang.org/docs/reference/properties.html#late-initialized-properties)、[インライン関数](https://kotlinlang.org/docs/reference/inline-functions.html#inline-functions)これを一般化する。私の試みはうまくいくはずですが、Kotlinのコンパイルのバグがありました(https://youtrack.jetbrains.com/issue/KT-10878を参照)。 – mfulton26

答えて

0

SelfProferenceを使用する代わりに、初期化子に引数(または受信者)が渡されるようにSelfReferenceを書き換える方法はありますか?この質問は、遅延評価された受信側/引数を関数に渡すか、このセマンティクスを何らかの方法で達成する方法があるか、与えholderActionは、受信機(Holder.() -> Unit)とラムダであるので、これは動作します

fun initHolder(x: Int = 0, holderAction: Holder.() -> Unit) : Holder { 
    var h: Holder? = null 
    h = Holder(x) { h!!.holderAction() } 
    return h 
} 

val h: Holder = initHolder(0) { x++ } 
h.action() 
h.action() 
println(h.x) // 2 

私は、私は完全にあなたのユースケースを理解していないが、これはあなたが探しているものかもしれ受信者のメンバーへのラムダアクセス。

Holderコンストラクタの署名を変更できない可能性があるため、これは一般的な解決方法です。この解決策では、クラスをオープンする必要がないことに注意する価値があります。そうでない場合は、セカンダリコンストラクタを使用してサブクラスで同様のアプローチを実行できます。

変更を必要とするクラスがほんの少数の場合は、SelfReferenceクラスを作成することをお勧めします。

有用なエラーを表示するために、!!を使用する代わりに、nullを確認するとよいでしょう。ホルダーがコンストラクタまたはinitブロック内のactionを呼び出すと、nullポインタ例外が発生します。