簡體   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