2016-12-15 5 views
0

なぜ次のコードでStackOverflowExceptionが生成されるのですか?入れ子にされたGroovyクロージャがStackOverflowExceptionを生成する

​Closure c0 = { 
    println "$this $owner $delegate" 
    Closure c1 = { 
    println "$this $owner $delegate" 
    } 
    c1() 
} 

c0()​ 

、出力は

java.lang.StackOverflowError 
    at Script1$_run_closure1$_closure2.doCall(Script1.groovy:5) 
    at Script1$_run_closure1$_closure2.doCall(Script1.groovy) 
    at Script1$_run_closure1.doCall(Script1.groovy:7) 
    at Script1$_run_closure1$_closure2.doCall(Script1.groovy:5) 
    at Script1$_run_closure1$_closure2.doCall(Script1.groovy) 
    at Script1$_run_closure1.doCall(Script1.groovy:7) 

答えて

0

あるにStackOverflowErrorは、内側の閉鎖の所有者デリゲートオブジェクトの失敗した文字列補間によって引き起こされています。

文字列補間の代わりに文字列連結を使用して、その値にアクセスできます。

あなたが行うことができます内側の閉鎖C1に

、:

println "$this " + owner + " " + delegate 

は、ここでは、このソリューションを実装し、また内側の両方のための「これ」、「所有者」と「デリゲート」の内容をダンプしますlink to an exampleですあなたは彼らがどのように異なっているかを見ることができます。

リンクにアクセスして[実行]ボタンをクリックすると結果が表示されます。

+0

ありがとう、私は思いますあなたは私の質問に答えました – ntviet18

0

あなたがこのようなスクリプトを分解した場合に何が起こっているかを確認するために簡単です:

Closure c0 = { 
    println "$this" 
    println "$owner" 
    println "$delegate" 
    Closure c1 = { 
    println "$this"  // breakpoint here 
    println "$owner" 
    println "$delegate" 
    } 
    c1() 
} 

c0() 

その後、示されているように、あなたのIDEにブレークポイントを設定し、デバッガを介して実行。次に、内部クロージャのownerdelegateの値が、実際には外側のクロージャであることがわかります。

通常、オブジェクトがGroovy GStringに補間されると、toString()メソッドが呼び出されますが、補間されたオブジェクトがクロージャである場合はそうではありません。 の場合、の場合、呼び出しシーケンスはobject.call().toString()です。したがって、クロージャc1c0は、無限ループ内でお互いを呼び出すことになります。

あなたを介してステップ3その後、( c0ownerを起動するために)バック私のライン2に私のライン7からのステッピング、動作中に、この効果を見ることができるデバッガで

、4、5(c1を定義する)、10 (c1を呼び出す)、6,7、そして再び2に戻ります。これを防止するために

、このように、より直接的に文字列にクロージャを強制:

println (owner as String) 

またはこの:

println (owner.toString()) 

またはこの:トレバーさんのように

println ("" + owner) 

(ソリューション)

関連する問題