[英]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、 strings
和values
,如果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.