简体   繁体   English

Groovy:在静态类闭包内部访问全局变量

[英]Groovy: Access global variables inside static class closures

I'm running the below code snippet and not sure how to resolve accessing the tr variable inside a static method of a class returning closure. 我正在运行下面的代码片段,并且不确定如何解决在返回闭包的类的static method中访问tr变量的问题。

tr = 'GROOVY'

class tmp {
    static map = {
        def cols = [ header: { "JAVA" }, trailer: { tr } ]
    }
}

tmp.map().collect { k,v -> println v()} 

Threw the below error when I ran it. 当我运行它时抛出以下错误。

JAVA
Caught: groovy.lang.MissingPropertyException: No such property: tr for class: tmp
Possible solutions: map
groovy.lang.MissingPropertyException: No such property: tr for class: tmp
Possible solutions: map
    at tmp$__clinit__closure1$_closure3.doCall(test.groovy:31)
    at tmp$__clinit__closure1$_closure3.doCall(test.groovy)
    at test$_run_closure1.doCall(test.groovy:35)
    at test.run(test.groovy:35)
[Finished in 2.0s with exit code 1]

Your static block is shared among all instances of class Tmp . 您的静态块在Tmp类的所有实例之间共享。 It is normal that the closure defined in this scope cannot access an instance variable of a specific instance, right? 通常,在此作用域中定义的闭包不能访问特定实例的实例变量 ,对吗?

However you can fix this by using the delegation mechanism in groovy closures. 但是,您可以通过在Groovy闭包中使用委托机制来解决此问题。

class Context {
    String tr="GROOVY"
}

class Tmp {
    static map = {
        def cols = [ header: { "JAVA" }, trailer: { tr } ]
    }
}

class Runner {
    void run(Context ctx) {
        //we need to clone this closure, because it is a shared (static) closure
        //other threads may try to run this method concurrently, and because
        //we are going to alter the closure's internal state by setting it's delegate
        Closure map=Tmp.map.clone()
        map.resolveStrategy=Closure.DELEGATE_FIRST
        map.delegate=ctx

        map().collect { k,v -> println "k:$k, v:${v()}"}
    }
}

new Runner().run(new Context())

Your groovy file is being compiled to something like this: 您的groovy文件正在被编译为如下所示:

class Script1 extends Script {

    class tmp {
        static map = {
            def cols = [ header: { "JAVA" }, trailer: { tr } ]
        }
    }

    def run() {
        tr = 'GROOVY'
        tmp.map().collect { k,v -> println v()} 
    }

}

Can you see why tr can't be found by class tmp ? 您能看到为什么class tmp找不到tr吗?

You can make use of the Groovy Binding class object. 您可以使用Groovy Binding类对象。 It is used to pass values in and out of the Groovy scripts. 它用于将值传入和传出Groovy脚本。 By default there is one readily usable binding object available for the scripts. 默认情况下,脚本有一个易于使用的绑定对象。 The properties declared outside the classes are added automatically to this object. 在类外部声明的属性将自动添加到此对象。

tr = 'GROOVY'

class Tmp {
    static Binding context
    static map = {
        def cols = [header: { "JAVA" }, trailer: { context.tr }]
    }
}

Tmp.context = binding
Tmp.map().collect { k, v -> println v() } 

It is better to create your own binding object (or should I say context) instead of relying on the default one as follows: 最好创建自己的绑定对象(或者我应该说上下文),而不是依赖于默认对象,如下所示:

def myBinding = new Binding(['tr': 'Groovy'])

class Tmp {
    static Binding context
    static map = {
        def cols = [header: { "JAVA" }, trailer: { context.tr }]
    }
}

Tmp.context = myBinding
Tmp.map().collect { k, v -> println v() }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM