2016-12-15 70 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最終以無限循環相互調用。

在調試器,你可以逐步並在行動中看到這種效果,從我的管線7返回到我的第2行步進(調用ownerc0),然後3,4,5(定義c1),10 (調用c1),6,7,再回到2。

爲了防止這種情況,更直接要挾關閉字符串,像這樣:

println (owner as String) 

或本:

println (owner.toString()) 

或本:

println ("" + owner) 

(如Trevor的解決方案)