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()
?
Ответы
Ответ 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() {
}
}