Подтвердить что ты не робот

Groovy scope - как получить доступ к переменной script в методе

У меня вопрос о правилах определения области видимости в Groovy. В следующем фрагменте у меня есть три переменные, a имеет локальную область видимости, b имеет область script, а c также должна обладать областью script, используя аннотацию @Field.

#!/usr/bin/groovy
import groovy.transform.Field;

//println org.codehaus.groovy.runtime.InvokerHelper.getVersion()

def a = 42;
b = "Tea"
@Field def c = "Cheese"

void func()
{
    // println a // MissingPropertyException
    println b // prints "Tea"
    println c // prints "Cheese" with groovy 2.1.2, MissingPropertyException with groovy 1.8.6

}

class Main
{
    def method()
    {
        // println a // MissingPropertyException
        // println b // MissingPropertyException
        // println c // MissingPropertyException with both 1.8.6. and 2.1.2
    }

}

func();
new Main().method();

Я получаю MissingPropertyException в строках, обозначенных комментариями. Исключения из a ожидаются, так как эта переменная имеет локальную область видимости. Но я ожидал бы, что b будет доступен внутри method() - это не так. @Field ничего не делает в groovy 1.8.6, хотя после обновления он работает, поэтому я думаю, что это старая ошибка. Тем не менее, c недоступен внутри method() с любой версией.

Итак, мои вопросы:

  • Почему я не могу получить доступ к переменной, аннотированной с помощью @Field внутри method()?
  • Как я могу ссылаться на переменную script внутри method()?
4b9b3361

Ответ 1

Когда у вас есть методы или заявления вне объявления class в groovy script, создается неявный класс. Чтобы ответить на ваши вопросы:

  • В вашем примере func() может получить доступ к полю c, потому что они оба являются членами неявного класса. Класс Main не является, поэтому он не может.

  • Вам нужно передать ссылку на переменную script на method(). Один из способов - передать неявно определенный объект binding, через который вы можете получить доступ ко всем переменным области видимости script.

Пример:

#!/usr/bin/groovy
import groovy.transform.Field;

//println org.codehaus.groovy.runtime.InvokerHelper.getVersion()

def a = 42;
b = "Tea"
@Field def c = "Cheese"

void func()
{
    // println a // MissingPropertyException
    println b // prints "Tea"
    println c // prints "Cheese" with groovy 2.1.2, MissingPropertyException with groovy 1.8.6

}

class Main
{
    def scriptObject
    def binding

    def method()
    {
        // println a // MissingPropertyException
        println binding.b
        println scriptObject.c
    }
}

func();
new Main(scriptObject: this, binding: binding).method();

Ответ 2

Эти script и Main генерируются как два отдельных класса внутри одного и того же файла.

Поскольку Main не является внутренним классом класса script, он не может видеть поле java.lang.Object c внутри класса script.

Вам придется либо явно переносить этот script в класс с помощью метода static main( args ) (и внутреннего класса Main), либо вам нужно передать экземпляр класса script методу, подобному: Main.method( this )

Это то, что приведено выше script:

class Script032034034 {
  Object c

  Script032034034() {
    c = 'Cheese'
  }

  Object run() {
    Object a = 42
    b = 'Tea'
    func()
    new Main().method()
  }

  void func() {
    println b
    println c
  }
}

class Main {
  Object method() {
  }
}