С точки зрения компилятора Groovy в вашем коде закрытия нет ошибок. Компилятор видит creditPoints : "288"
как помеченный оператор , который является допустимой конструкцией в языке программирования Groovy. Как говорится в документации, оператор label ничего не добавляет к результирующему байт-коду, но он может использоваться, например, преобразованиями AST (Spock Framework активно его использует).
Становится более понятным и легким для понимания, если вы более точно форматируете код в сценарии использования оператора label, например,
class Simple {
String creditPoints
static void main(String[] args) {
Simple simple = new Simple()
simple.with {
creditPoints:
"288"
}
println simple
}
}
(ПРИМЕЧАНИЕ. Я поместил ваш скрипт в тело метода main
, чтобы показать его представление байт-кода в следующем разделе.)
Теперь, когда мы знаем, как компилятор видит эту конструкцию, давайте посмотрим, как будет выглядеть финальный байт-код. Для этого мы декомпилируем файл .class
(для этого я использую IntelliJ IDEA - вы просто открываете файл .class
в IDEA, и он декомпилирует его для вас):
//
// 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"
, что ожидается - последний оператор замыкания по умолчанию становится оператором возврата. В сгенерированном байт-коде нет оператора метки, что также ожидается, когда метки будут удалены на этапе CANONICALIZATION
Groovy-компилятора.