37

我对 Groovy 中的范围规则有疑问。在下面的代码片段中,我有三个变量,a具有本地范围,b具有脚本范围,并且c应该使用@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在注释指示的行上得到 s。预计会出现异常a,因为该变量具有本地范围。但我希望b内部可以访问method()- 它不是。 @Field在 groovy 1.8.6 中没有做任何事情,尽管升级后它可以工作,所以我猜这是一个老错误。然而,无论哪个版本c都无法访问内部method()

所以我的问题是:

  1. 为什么我不能访问用@Fieldinside 注释的变量method()
  2. 如何引用里面的脚本变量method()
4

2 回答 2

37

当您在 groovy 脚本中的声明之外有方法或语句时class,会创建一个隐式类。要回答您的问题:

  1. 在您的示例中,func()可以访问该字段c,因为它们都是隐式类的成员。类Main不是,所以它不能。

  2. 您需要将对脚本变量的引用传递给method(). 一种方法是传递隐式定义的binding对象,通过它您可以访问所有脚本范围变量。

例子:

#!/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();
于 2013-03-25T16:26:41.643 回答
10

该脚本Main在同一个文件中生成为两个单独的类。

由于Main不是 Script 类的内部类,所以它看不到 Script 类java.lang.Object c内部的字段。

您要么必须将此脚本显式包装在具有static main( args )方法(和内部Main类)的类中,要么需要将脚本类的实例传递给方法,例如:Main.method( this )

这是上面脚本生成的那种东西:

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() {
  }
}
于 2013-03-25T16:28:30.617 回答