#groovy #closures
#groovy #замыкания
Вопрос:
У меня есть следующий код:
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. Я получил это с вашим кодом «Simple (creditPoints: null)»
Ответ №1:
С точки зрения компилятора Groovy, в вашем коде замыкания нет ошибки. Компилятор видит оператор с надписью creditPoints : "288"
as , который является допустимой конструкцией в языке программирования 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"
ожидаемую строку — последний оператор замыкания становится оператором return по умолчанию. В сгенерированном байт-коде отсутствует оператор label, что также ожидается, поскольку метки удаляются на CANONICALIZATION
этапе компиляции Groovy.