【问题标题】:Groovy scope - how to access script variable in a methodGroovy 范围 - 如何在方法中访问脚本变量
【发布时间】:2013-03-25 15:54:53
【问题描述】:

我对 Groovy 中的范围规则有疑问。在下面的 sn-p 中,我有三个变量,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();

我在 cmets 指示的行上得到 MissingPropertyExceptions。 a 上的异常是预期的,因为该变量具有本地范围。但我希望b 可以在method() 内部访问——它不是。 @Field 在 groovy 1.8.6 中没有做任何事情,尽管升级后它可以工作,所以我猜这是一个老错误。然而,cmethod() 中是不可访问的。

所以我的问题是:

  1. 为什么我不能访问内部带有@Field 注释的变量 method()?
  2. 如何在method() 中引用脚本变量?

【问题讨论】:

    标签: groovy scope


    【解决方案1】:

    当您在 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();
    

    【讨论】:

    • 很确定您的意思是将这些 scriptObject 和绑定参数传递给构造函数,例如 "new Main( scriptObject: this, binding: binding ).method()"
    【解决方案2】:

    此脚本和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() {
      }
    }
    

    【讨论】:

    • 感谢生成的代码sn-p,这对我的理解有很大帮助。我的误解是我认为 Main 将是 Script032034034 的子类。
    • 在您提供的代码中,func() 如何“看到”bb 也是 Script 类的属性吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-22
    • 1970-01-01
    • 2019-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-15
    相关资源
    最近更新 更多