Groovy'with'方法的异常行为-变量分配静默失败

时间:2019-03-28 01:38:05

标签: groovy closures

我有以下代码:

import groovy.transform.ToString
@ToString(includeNames = true)
class Simple {
  String creditPoints
}
Simple simple = new Simple()
simple.with {
    creditPoints : "288"
}
println simple

很显然,我在creditPoints : "288"处犯了一个错误。应该是creditPoints = "288"

我期望Groovy在运行时失败,说我犯了一个错误,应该使用creditPoints = "288",但显然没有。

既然没有失败,那么Groovy对我创建的闭包做了什么?

1 个答案:

答案 0 :(得分:1)

从Groovy编译器的角度来看,您的关闭代码没有错误。编译器将creditPoints : "288"视为labeled statement,这是Groovy编程语言中的合法构造。如文档所述,label语句不会在生成的字节码中添加任何内容,但是可以用于AST转换(例如Spock Framework大量使用它)。

例如,如果您更准确地格式化标签声明用例的代码格式,它将变得更加清晰和易于理解

class Simple {
    String creditPoints

    static void main(String[] args) {

        Simple simple = new Simple()
        simple.with {
            creditPoints:
            "288"
        }
        println simple
    }
}

(注意:我将您的脚本放入main方法主体中,以在下一节向您显示其字节码表示形式。)

现在,当我们知道编译器如何看待这种构造时,让我们看一看,看看最终的字节码是什么样子。为此,我们将对.class文件进行反编译(我使用IntelliJ IDEA-您只需在IDEA中打开.class文件并为您反编译):

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

import groovy.lang.Closure;
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import groovy.transform.ToString;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
import org.codehaus.groovy.runtime.GeneratedClosure;
import org.codehaus.groovy.runtime.InvokerHelper;

@ToString
public class Simple implements GroovyObject {
    private String creditPoints;

    public Simple() {
        MetaClass var1 = this.$getStaticMetaClass();
        this.metaClass = var1;
    }

    public static void main(String... args) {
        Simple simple = new Simple();

        class _main_closure1 extends Closure implements GeneratedClosure {
            public _main_closure1(Object _outerInstance, Object _thisObject) {
                super(_outerInstance, _thisObject);
            }

            public Object doCall(Object it) {
                return "288";
            }

            public Object call(Object args) {
                return this.doCall(args);
            }

            public Object call() {
                return this.doCall((Object)null);
            }

            public Object doCall() {
                return this.doCall((Object)null);
            }
        }

        DefaultGroovyMethods.with(simple, new _main_closure1(Simple.class, Simple.class));
        DefaultGroovyMethods.println(Simple.class, simple);
        Object var10000 = null;
    }

    public String toString() {
        StringBuilder _result = new StringBuilder();
        Boolean $toStringFirst = Boolean.TRUE;
        _result.append("Simple(");
        if ($toStringFirst == null ? false : $toStringFirst) {
            Boolean var3 = Boolean.FALSE;
        } else {
            _result.append(", ");
        }

        if (this.getCreditPoints() == this) {
            _result.append("(this)");
        } else {
            _result.append(InvokerHelper.toString(this.getCreditPoints()));
        }

        _result.append(")");
        return _result.toString();
    }

    public String getCreditPoints() {
        return this.creditPoints;
    }

    public void setCreditPoints(String var1) {
        this.creditPoints = var1;
    }
}

如您所见,与with方法一起使用的闭包被表示为内部_main_closure1类。此类扩展了Closure类,并且实现了GeneratedClosure接口。闭包的主体封装在public Object doCall(Object it)方法中。此方法仅返回"288"字符串,这是预期的-默认情况下,闭包的最后一条语句成为return语句。生成的字节码中没有label语句,在CANONICALIZATION Groovy编译器阶段剥离标签时,也期望这样做。