Достъп до GroovyScript Field в анонимен клас

В скрипт Groovy 2.1.6 дефинирам поле:

import groovy.transform.Field
@Field String test = "abc";

println "Script: ${test}";
def run = new Runnable() {
    void run() {
        println "Runnable0: ${test}";
        new Runnable() {
            void run() {
                println "Runnable1: ${test}";
            }
        }.run();
    }
}.run();

При достъп до него от анонимен клас в скрипта като тук, Groovy изглежда се опитва да прехвърли това поле към препратка и хвърля следното изключение веднага след дефиниране на Runnable:

org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'abc' with class 'java.lang.String' to class 'groovy.lang.Reference'
    at bug1.run(bug1:5)

Освен това, ако поставя анонимните Runnables във функция като тук, Groovy няма проблеми с кастинга, но не намерете полето във вътрешния Runnable:

groovy.lang.MissingFieldException: No such field: test for class: bug2$1
    at bug2$1.this$dist$get$1(bug2.groovy)
    at bug2$1$2.propertyMissing(bug2.groovy)
    at bug2$1$2.run(bug2.groovy:14)
    at java_lang_Runnable$run.call(Unknown Source)
    at bug2$1.run(bug2.groovy:12)
    at java_lang_Runnable$run.call(Unknown Source)
    at bug2.fun(bug2.groovy:9)
    at bug2.run(bug2.groovy:5)

Това може да бъде коригирано чрез предефиниране на полето като тук, но тази корекция работи само във функция

Това грешка в Groovy ли е или просто нарушавам някои правила и Groovy няма само подходящи изключения?


person NCode    schedule 10.09.2013    source източник


Отговори (2)


Не се нуждаете от трансформация @Field в случай, че извиквате анонимен клас и препращате променливата на полето.

Причина:
Когато строго въведена променлива в скрипт е дефинирана като @Field, тогава тази променлива (по време на компилиране [AST трансформирано]) се третира като частна в този скрипт. Следователно липсва собственост.

За да осъзнаете разликата, просто визуализирайте скрипта в AST браузър от конзолата Groovy и преминете през фазата на „Семантичен анализ“ и в двата случая (без и с @Field), ще забележите, че променливата е локална за run() за основния скрипт в сравнение с дефинираните глобално по друг начин съответно.

Последствие:
От друга страна, трансформацията @Field е полезна, когато трябва да се използват строго въведени променливи в метод в същия скрипт, защото без @Field полето ще бъде декларирано като локална променлива в run() метод на скрипта, следователно не се вижда от други методи.

Извадки от AST браузър за подробности.

person dmahapatro    schedule 10.09.2013

Тъй като затварянията на Groovy вече са Runnables, можете да направите:

import groovy.transform.Field
@Field String test = "abc";

println "Script: ${test}";
{ -> 
    println "Runnable0: ${test}";
    { -> 
        println "Runnable1: ${test}"
    }.run()
}.run()

Което работи

person tim_yates    schedule 10.09.2013