[英]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.