为什么以下代码会产生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 :(得分:0)
StackOverFlowError是由内部闭包 所有者 和 委托 对象。
您可以使用字符串连接而不是字符串插值来访问它们的值。
在内部闭包c1中,你可以这样做:
println "$this " + owner + " " + delegate
这是一个实现此解决方案的link to an example,并且还会删除“这个'”所有者'的内容。并且'委托'对于内部和外部闭合,您可以看到它们是如何不同的。
访问该链接,然后点击“执行”按钮。按钮查看结果。
答案 1 :(得分:0)
如果您像这样分解脚本,则更容易看到正在发生的事情:
There was a failure to launch the remote debugger
然后按照指示在IDE中设置断点,并通过调试器运行它。然后你可以看到内部闭包中的Closure c0 = {
println "$this"
println "$owner"
println "$delegate"
Closure c1 = {
println "$this" // breakpoint here
println "$owner"
println "$delegate"
}
c1()
}
c0()
和owner
值实际上是外部闭包。
现在,通常,当一个对象被内插到Groovy GString中时,会调用delegate
方法,但当插值对象是一个闭包时,情况并非如此。在那个的情况下,调用序列是toString()
。因此,闭包object.call().toString()
和c1
最终会在无限循环中相互调用。
在调试器中,你可以单步执行并看到这个效果,从我的第7行步回到第2行(调用c0
,owner
),然后是3,4,5 (定义{{1}}),10(调用c0
),6,7,再返回2。
为了防止这种情况,请更直接地将闭包强制转换为字符串,如下所示:
c1
或者这个:
c1
或者这个:
println (owner as String)
(如特雷弗的解决方案)