繁体   English   中英

在 Groovy 闭包中调用 Owner 时的递归

[英]Recursion when calling Owner in Groovy Closure

我一直在尝试理解 Groovy 脚本,但我举的一个例子遇到了意外的 StackOverflow。

在定义另一个名为 bar 的闭包之前,foo 闭包将其所有者打印为“Tank”。 我希望 bar 将所有者打印为 Tank$foo 之类的东西。

class Tank {
    def foo = {
        println "Owner is $owner"

        def bar = {
            println "      Owner is $owner"
        }
        bar()
    }

    static void main(String ...args){
        def t = new Tank() ;
        t.foo()
    }
}

好吧......简短的回答是你应该将你的bar方法更改为以下内容:

def bar = {
    println "      Owner is ${owner.toString()}"
}

这将防止评估$owner引用的foo闭包。 因为它将不再是一个闭包,而是它的一个字符串表示。 这就是您想在示例中实现的目标。

完整的答案有点太复杂并且有它的历史......

Groovy 中的字符串插值是使用GString class 实现的。当编译器遇到您的" Owner is $owner"时,它首先将该值分解为不同的部分,其中" Owner is "作为string保存,而$owner转到 -称为价值观。 这就是GString实例的构造方式,它是这两个部分的组合。

如果我们查看 Groovy 源代码,我们可以看到GString.toString()是如何求值的。 现有的实现遍历 arrays、 stringsvalues ,如果value是一个闭包,那么它只是急切地评估(调用)那个。 这就是为什么您陷入示例中的无限递归。 这是在Groovy 源代码中找到的GString.toString()片段(找到c.call(...) ):

if (value instanceof Closure) {
    final Closure c = (Closure) value;

    if (c.getMaximumNumberOfParameters() == 0) {
        InvokerHelper.write(out, c.call());
    } else if (c.getMaximumNumberOfParameters() == 1) {
        c.call(out);
    } else {
        throw new GroovyRuntimeException("Trying to evaluate a GString containing a Closure taking "
                + c.getMaximumNumberOfParameters() + " parameters");
    }
} else {
    InvokerHelper.write(out, value);
}

有趣的是,我还发现这是什么时候首次引入的,以及关于可能改变这种行为的讨论。 讨论问题仍未解决。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM