为什么在字符串中打印闭包的所有者会导致无限递归



我在玩闭包,看到了我无法完全解释的奇怪行为:

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有关,因为我从未在其他变量/表达式中看到过这种情况。有什么想法吗?

当闭包嵌入到GString中时,与嵌入在GString的变量不同,不会在闭包上调用toString()。在上面看到错误的情况下,owner是周围的闭包,toString()不会在闭包上调用。

为了绕过它,必须在owner上显式调用toString(),如:

({ ({ println "${owner.toString()}" })() })()

这同样适用于我们构建的嵌套级别的闭包。

({ ({ ({ println "${owner.toString()}" })() })() })()

如果有适当的缩进,它看起来像:

({ 
    ({ 
        ({ 
            println "${owner.toString()}" 
        })() 
    })() 
})()

这种行为可以用一个微不足道的例子来解释。

def clos = {return {"hello"}}
println "${clos()}" //prints nothing
println "${clos()()}" //prints hello

错误解释:-
现在来谈谈所面临的错误,如前所述,当闭包嵌入GString中时,不会在闭包上调用toString()。相反,调用闭包,然后对调用的闭包的结果调用/应用toString()。意思是:

CCD_ 11相当于CCD_。

在上面的情况下,在调用外部闭包时,它最终通过GString实现["$owner"]调用自己,并且调用作为递归增长,因此出现了stackerflow错误。

注意:
当应用GString的变量很简单时,可以省略{}。CCD_ 15与CCD_。只要访问变量的简单属性,就可以执行此操作。"$myVariable.class.name"是好的(只要myVariable不是映射)。但是当涉及方法调用时,需要大括号"${myVariable.toString()}"

最新更新