Why does printing the owner of a closure in a string cause infinite recursion?

前端 未结 1 726
广开言路
广开言路 2021-01-19 10:23

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

groovy:000> ({ println owner })()
groovysh_evaluate@200b6145
===>          


        
相关标签:
1条回答
  • 2021-01-19 10:51

    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.

    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
    

    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" is equivalent to owner().toString().

    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.

    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()}"

    0 讨论(0)
提交回复
热议问题