4

我正在玩闭包并看到这种我无法解释的奇怪行为:

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因为我没有看到它发生在其他变量/表达式中。有任何想法吗?

4

1 回答 1

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"] 调用自身,并且调用作为递归增长,因此出现 stackoverflow 错误。

注意:当您应用 GString 的变量很简单时,
您可以省略。与 相同。只要您访问变量的简单属性,您就可以这样做。很好(只要 myVariable 不是地图)。但是当涉及方法调用时,需要花括号{}"${myVariable}""$myVariable""$myVariable.class.name""${myVariable.toString()}"

于 2013-07-28T03:55:13.143 回答