在groovy中查找闭包的自由变量列表/映射

在groovy中查找闭包的自由变量列表/映射,groovy,properties,closures,free-variable,Groovy,Properties,Closures,Free Variable,这是我的简单groovy脚本 def fourtify(String str) { def clsr = { str*4 } return clsr } def c = fourtify("aa") println("binding variables: ${c.getBinding().getVariables()}") ... 我在这里要做的就是能够使用closure实例访问自由变量“str”,从而更好地理解closure在幕后的工作方式。比

这是我的简单groovy脚本

def fourtify(String str) {

    def clsr = {
         str*4
    }

    return clsr
}

def c = fourtify("aa")
println("binding variables: ${c.getBinding().getVariables()}")
...
我在这里要做的就是能够使用closure实例访问自由变量“
str
”,从而更好地理解closure在幕后的工作方式。比如Python的
locals()
方法


有办法做到这一点吗?

您定义的闭包不在
绑定
对象中存储任何内容-它只返回作为
str
变量传递的字符串,重复4次

binding
对象存储所有定义的变量,而不指定其类型或使用
def
关键字。它是通过Groovy元编程特性完成的(
getProperty
setProperty
方法更具体)。因此,当您定义变量
s
时,如下所示:

def clsr={
s=str*4
返回s
}
然后,这个闭包将创建一个带有键
s
和从表达式
str*4
计算的值的绑定。这个绑定对象只是一个通过
getProperty
setProperty
方法访问的映射。因此,当Groovy执行
s=str*4
时,它调用
setProperty('s',str*4)
,因为变量/property
s
没有定义。如果我们做一个稍微简单的改变,比如:

def clsr={
def s=str*4//或字符串s=str*4
返回s
}
然后将不会创建绑定
s
,因为
setProperty
方法不会执行

对你的例子的另一个评论。若您想在binding对象中看到任何内容,则需要调用返回的闭包。在上面显示的示例中,将返回闭包,但从未调用它。如果您这样做:

def c = fourtify("aa")
c.call()
println("binding variables: ${c.getBinding().getVariables()}")
然后调用闭包,绑定对象将包含绑定(如果有)。现在,如果您将示例修改为以下内容:

def fourtify(String str) {

    def clsr = {
        def n = 4 // it does not get stored as binding
        s = str * n
        return s
    }

    return clsr
}

def c = fourtify("aa")
c.call()
println("binding variables: ${c.getBinding().getVariables()}")
作为回报,您将看到以下输出:

binding variables: [args:[], s:aaaaaaaa]

希望有帮助。

在您的示例中,
str
是方法/函数的参数
fortify

但是,以下示例可能会让您更好地理解:

def c={ String s,int x-> return s*x }

println( c.getClass().getSuperclass() )     // groovy.lang.Closure
println( c.getMaximumNumberOfParameters() ) // 2
println( c.getParameterTypes() )            // [class java.lang.String, int]
locals()

下面是一个简单的脚本示例:

Script scr = new GroovyShell().parse(''' 
    println this.getBinding().getVariables()  // print "s" and "x"
    z = s*(x+1)                               // declare a new script-level var "z"
    println this.getBinding().getVariables()  // print "s", "x", and "z"
    return s*x 
''')
scr.setBinding( new Binding([
        "s":"ab",
        "x":4
    ]) )
println scr.run() // abababab
println scr.getBinding().getVariables() // print "s", "x", and "z"

这就是我在开始时所想的,所以我尝试在闭包实例上使用getBinding()方法获取变量(包括“自由”变量)。此外,我更感兴趣的是在编译脚本后获取闭包关闭的“自由”变量,而不是检索有关参数的信息。@zgulser,闭包没有“自由”变量。使用
delegate
可以访问声明此闭包的对象,并使用groovy元类请求声明的类字段:
delegate.metaclass.properties.collect{it.name}
或使用java native
delegate.getClass().getDeclaredFields()
。但是,您不能访问在方法/函数中声明的局部变量。我不认为这是完全正确的-。我知道Groovy中的委托概念,但在我的情况下,我认为“str”不能是任何委托的一部分,因为它是函数的局部变量。在您的示例中,无法获取
str
it。除非你想用AstBuilder来分析代码……我明白你的意思,但我还是不明白为什么我在任何地方都看不到“free”变量“str”——即使在我删除了类型字符串之后?我的观点是,在编译脚本时,变量“str”应该存储在某个地方,因此当我调用闭包时,它可以通过查看所有者或委托或其他对象来解析“str”名称。希望它更有意义。