4

在 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 只是缺少适当的异常?

4

2 回答 2

2

如果您调用匿名类并引用字段变量,则不需要@Field转换。

原因:
当脚本中的严格类型变量被定义@Field为时,该变量(在编译时 [AST 转换])在该脚本中被视为私有变量。因此财产丢失。

为了实现差异,只需从 Groovy 控制台可视化 AST 浏览器中的脚本,并在两种情况下(不带和带 @Field)都经过“语义分析”阶段,您会注意到该变量run()对于主脚本来说是本地的与分别在全球范围内定义的相比。

推论
另一方面,@Field当要在同一脚本内的方法中使用严格类型的变量时,转换很有用,因为没有@Field该字段将在run()脚本的方法中声明为局部变量,因此对其他方法不可见。

摘自AST 浏览器以获取详细信息。

于 2013-09-10T19:02:10.093 回答
0

由于 Groovy 闭包Runnable已经是 s,您可以这样做:

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

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

哪个有效

于 2013-09-10T19:40:57.093 回答