为什么在字符串中打印闭包的所有者会导致无限递归? [英] Why does printing the owner of a closure in a string cause infinite recursion?

查看:97
本文介绍了为什么在字符串中打印闭包的所有者会导致无限递归?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在玩封闭,看到这种奇怪的行为,我不能解释:

I'm playing with closures and seeing this odd behavior that I can't quite explain:

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

I figure it has something to do with the fact that the ${} is itself a closure, but I can't quite pin down why this happens. The issue does appear related to accessing owner as I've not seen it happen with other variables/expressions. Any ideas?

推荐答案

如果一个闭包嵌入一个GString, toString code>不是在嵌入在GString中的变量而不是在闭包。在上面的情况下,你看到一个错误, owner 是周围的闭包和 toString()封闭。

In cases when a closure is embedded inside a GString, toString() is not called on the closure unlike variables embedded in GString. In the above case where you see an error, owner is the surrounding closure and toString() would not be called on the closure.

为了解决这个问题, toString()必须在 owner like:

To get around with it, toString() has to be called explicitly on owner like:

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

这同样适用于我们构建的许多嵌套层次的闭包。

The same is applicable for as many nested level of closures we build.

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

使用适当的缩进格式如下:

With proper indentation it would look like:

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

行为可以用一个简单的例子解释。

The behavior can be explained with a trivial example.

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

错误: -

现在遇到的错误是,如前所述,当一个闭包嵌入到GString中时, toString()不会在闭包上调用。而是调用闭包,然后对调用闭包的结果调用/应用 toString()。这意味着:

Explanation for error:-
Now coming to the error that is faced, as mentioned earlier, when a closure is embedded inside GString, toString() is not called on the closure. Instead the closure is called and then toString() is invoked/applied on the result of the called closure. Which means:

$ owner等效于 owner )

在上面的例子中,调用外部闭包时,它最终通过GString实现调用[$ owner],并且调用作为递归增长,因此出现stackoverflow错误。

In the above case, while calling the outer closure it eventually calls itself through the GString implementation ["$owner"] and the call grows as a recursion, hence a stackoverflow error.

注意:

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

Note:
You can omit {} when the variable on which you are applying GString is simple. "${myVariable}" is same as "$myVariable". You can do that as long as you are accessing simple properties of the variable. "$myVariable.class.name" is good (as long as myVariable is not a map). But when method calls are involved curly braces are needed "${myVariable.toString()}"

这篇关于为什么在字符串中打印闭包的所有者会导致无限递归?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆