簡體   English   中英

Groovy 閉包不會修改委托對象中的值

[英]Groovy closure does not modify a value in delegated object

下面顯示的 Groovy 代碼包含閉包和一個方法。 該格式更改標簽並期望收到該更改標簽顯示了問題和要求。

def method (String a, Closure c) {
    Query q = new Query()
    q.a = a
    c.delegate = q
    c.call()
    def str = q.str
}
class Query
{
    def str
    def a
    void key (String str, Closure cls) {
        this.str = str
        Pass p = new Pass()
        p.a=a
        cls.delegate=p
        cls.call()
        def val=p.a      // Expcted to receive that change
        println val

    } 
    class Pass
    {
        String a
    } 
}

method("got") {
    key ("got"){
        a=a.toUpperCase() // Format Changed here
        println a

    }
}

實際輸出是:

GOT
got

但我的預期輸出是:

GOT
GOT

為什么a = a.toUpperCase()cls.call()之后不會改變p對象中的值? 如何傳遞這種變化?

您必須將key(String str, Closure cls)方法中cls委托解析策略更改為:

cls.resolveStrategy = Closure.DELEGATE_FIRST

默認策略是Closure.OWNER_FIRST 在 Groovy 腳本的情況下,這意味着此閉包的所有者是由 Groovy 生成以運行腳本的類的實例。 對於您的 Groovy 腳本,該類如下所示:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import groovy.lang.Binding;
import groovy.lang.Closure;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.GeneratedClosure;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
import org.codehaus.groovy.runtime.callsite.CallSite;

public class my_groovy_script extends Script {
    public my_groovy_script() {
        CallSite[] var1 = $getCallSiteArray();
    }

    public my_groovy_script(Binding context) {
        CallSite[] var2 = $getCallSiteArray();
        super(context);
    }

    public static void main(String... args) {
        CallSite[] var1 = $getCallSiteArray();
        var1[0].call(InvokerHelper.class, my_groovy_script.class, args);
    }

    public Object run() {
        CallSite[] var1 = $getCallSiteArray();
        class _run_closure1 extends Closure implements GeneratedClosure {
            public _run_closure1(Object _thisObject) {
                CallSite[] var3 = $getCallSiteArray();
                super(my_groovy_script.this, _thisObject);
            }

            public Object doCall(Object it) {
                CallSite[] var2 = $getCallSiteArray();
                class _closure2 extends Closure implements GeneratedClosure {
                    public _closure2(Object _thisObject) {
                        CallSite[] var3 = $getCallSiteArray();
                        super(_run_closure1.this, _thisObject);
                    }

                    public Object doCall(Object it) {
                        CallSite[] var2 = $getCallSiteArray();
                        Object var3 = var2[0].call(var2[1].callGroovyObjectGetProperty(this));
                        ScriptBytecodeAdapter.setGroovyObjectProperty(var3, _closure2.class, this, (String)"a");
                        return var2[2].callCurrent(this, var2[3].callGroovyObjectGetProperty(this));
                    }

                    public Object doCall() {
                        CallSite[] var1 = $getCallSiteArray();
                        return this.doCall((Object)null);
                    }
                }

                return var2[0].callCurrent(this, "got", new _closure2(this.getThisObject()));
            }

            public Object doCall() {
                CallSite[] var1 = $getCallSiteArray();
                return this.doCall((Object)null);
            }
        }

        return var1[1].callCurrent(this, "got", new _run_closure1(this));
    }

    public Object method(String a, Closure c) {
        CallSite[] var3 = $getCallSiteArray();
        Query q = (Query)ScriptBytecodeAdapter.castToType(var3[2].callConstructor(Query.class), Query.class);
        ScriptBytecodeAdapter.setGroovyObjectProperty(a, my_groovy_script.class, q, (String)"a");
        ScriptBytecodeAdapter.setGroovyObjectProperty(q, my_groovy_script.class, c, (String)"delegate");
        var3[3].call(c);
        Object str = var3[4].callGroovyObjectGetProperty(q);
        return str;
    }
}

正如您所看到的,每個 Groovy 腳本實際上都是一個擴展groovy.lang.Script類的類。 這個類有一件重要的事情 - 它覆蓋:

如果您查看這兩種方法的源代碼,您將看到它使用binding對象來存儲和訪問閉包范圍內的所有變量。 這就是為什么您傳遞給Query.key(String str, Closure cls)不會修改Passa字段,而是創建a具有值GOT的本地綁定a 您可以通過將 Closure 的解析策略更改為Closure.DELEGATE_FIRST來更改此行為。 這將cls.delegate ,因為您明確地將cls.delegate設置為p instance,因此閉包將首先在p instance 中查找字段a 我希望它有幫助。

更新的 Groovy 腳本

def method(String a, Closure c) {
    Query q = new Query()
    q.a = a
    c.delegate = q
    c.call()
    def str = q.str
}

class Query {
    def str
    def a

    void key(String str, Closure cls) {
        this.str = str
        Pass p = new Pass()
        p.a = a
        cls.delegate = p
        cls.resolveStrategy = Closure.DELEGATE_FIRST
        cls.call()
        def val = p.a      // Expcted to receive that change
        println val

    }

    class Pass {
        String a
    }
}

method("got") {
    key("got") {
        a = a.toUpperCase() // Format Changed here
        println a

    }

輸出

GOT
GOT

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM