我正在玩闭包,看到这种奇怪的行为,我无法解释:
groovy:000> ({ println owner })()
groovysh_evaluate@200b6145
===> null
groovy:000> ({ println "${owner}" })()
groovysh_evaluate@2bf75a70
===> null
groovy:000> ({ ({ println owner })() })()
groovysh_evaluate$_run_closure1@10f67a01
===> null
groovy:000> ({ ({ println "${owner}" })() })()
ERROR java.lang.StackOverflowError:
null
at groovysh_evaluate$_run_closure1_closure2.doCall (groovysh_evaluate:2)
at groovysh_evaluate$_run_closure1_closure2.doCall (groovysh_evaluate)
at groovysh_evaluate$_run_closure1.doCall (groovysh_evaluate:2)
at groovysh_evaluate$_run_closure1_closure2.doCall (groovysh_evaluate:2)
at groovysh_evaluate$_run_closure1_closure2.doCall (groovysh_evaluate)
at groovysh_evaluate$_run_closure1.doCall (groovysh_evaluate:2)
<stacktrace repeats>
我认为它与${}
本身就是一个闭包这一事实有关,但我无法确定为什么会发生这种情况。该问题似乎与访问owner
有关,因为我没有看到它与其他变量/表达式一起发生。有什么想法吗?
答案 0 :(得分:4)
如果在GString中嵌入了闭包,则不会在闭包中调用toString()
,而不像GString中嵌入的变量。在上面你看到错误的情况下,owner
是周围的闭包,并且在闭包上不会调用toString()
。
要解决此问题,必须在toString()
上明确调用owner
,如:
({ ({ println "${owner.toString()}" })() })()
同样适用于我们构建的多个嵌套级别的闭包。
({ ({ ({ println "${owner.toString()}" })() })() })()
通过适当的缩进,它看起来像:
({
({
({
println "${owner.toString()}"
})()
})()
})()
可以用一个简单的例子来解释这种行为。
def clos = {return {"hello"}}
println "${clos()}" //prints nothing
println "${clos()()}" //prints hello
错误说明: -
现在遇到面临的错误,如前所述,当一个闭包嵌入在GString中时,关闭时不会调用toString()
。而是调用闭包,然后在被调用闭包的结果上调用/应用toString()
。这意味着:
"$owner"
相当于owner().toString()
。
在上面的例子中,在调用外部闭包时,它最终通过GString实现["$owner"
]调用自身,并且调用增长为递归,因此发生堆栈溢出错误。
注意:
当您应用GString的变量很简单时,可以省略{}
。 "${myVariable}"
与"$myVariable"
相同。只要您访问变量的简单属性,就可以这样做。 "$myVariable.class.name"
很好(只要myVariable不是地图)。但是当涉及方法调用时,需要大括号"${myVariable.toString()}"