简体   繁体   English

为什么在Groovy闭包中设置的实例变量的值在其外部不可见?

[英]Why is the value of the instance variable set in a Groovy closure not visible outside of it?

Question

Why does methodA() print set within run instead of set within closure ? 为什么methodA()打印set within run而不是set within closureset within closure

Code example 代码示例

class GroovyClosureVariableScopingTest extends Script {

    String s

    Object run() {
        s = "set within run"
        println "value of s in run(): $s"

        [1].each {
            s = "set within closure"
            println "value of s in each()-closure: $s"
            methodA()
        }
    }

    void methodA() {
        println "value of s in methodA(): $s"
    }
}

Actual output 实际输出

value of s in run(): set within run
value of s in each()-closure: set within closure
value of s in methodA(): set within run            // <- Surprised to see the original value

Expected output 预期产出

value of s in run(): set in run
value of s in each()-closure: set within closure
value of s in methodA(): set within closure        // <- Whould have expected this value

Elaboration

I haven't quite understood how variable scoping works in the above example. 我还不太清楚变量作用域如何在上面的例子中起作用。 I would have expected s to be a property (a public instance variable) of the class and I thought that I was assigning it a value from within the each -closure which would be retained. 我本来希望s是类的一个属性(一个公共实例变量),我认为我从each -closure中分配了一个值,这个值将被保留。 But that does not seem to be the case. 但事实似乎并非如此。

Why does s not keep the value which it was assigned from within the closure? 为什么s不保留从闭包中分配的值?

Solution / workaround 解决方案/解决方法

Passing s as argument to methodA() works. s作为参数传递给methodA()有效。 See lines commented with // Change . 请参阅// Change评论的行。

class GroovyClosureVariableScopingTest extends Script {

    String s

    Object run() {
        s = "set within run"
        println "value of s in run(): $s"

        [1].each {
            s = "set within closure"
            println "value of s in each()-closure: $s"
            methodA(s)              // Change
        }
    }

    void methodA(s) {               // Change
        println "value of s in methodA(): $s"
    }
}

Reference 参考

Closures - Formal Definition 闭包 - 正式定义

At the same time, the variables are still available normally to the enclosing scope, so the closure may read/change any such values, and code from the outer scope may read/change the same variables. 同时,变量仍然可以正常地用于封闭范围,因此闭包可以读取/更改任何这样的值,并且来自外部范围的代码可以读取/更改相同的变量。

Versions 版本

  • Groovy 1.8.6 Groovy 1.8.6
  • Groovy-Eclipse plugin 2.8.0 Groovy-Eclipse插件2.8.0
  • Eclipse Platform 3.8.1 Eclipse Platform 3.8.1

After user cfrick confirmed that it works on his machine, I ran it from the console and it indeed works. 用户cfrick确认它在他的机器上工作后,我从控制台运行它确实有效。

From console 从控制台

C:\temp>java -jar C:\...\lib\groovy-all-1.8.6.jar C:\temp\GroovyClosureVariableScopingTest.groovy
value of s in run(): set within run
value of s in each()-closure: set within closure
value of s in methodA(): set within closure // <- Here

With clean Eclipse installation 使用干净的Eclipse安装

But I still don't get the original script to run with a clean installation of 但我仍然没有得到原始脚本与干净安装运行

Summary 摘要

I still don't know why it doesn't work -- even with a clean installation of Eclipse. 我仍然不知道为什么它不起作用 - 即使是干净的Eclipse安装。 However, it works from the console, it works on cfrick's machine and there is a workaround. 但是,它可以在控制台上运行,它可以在cfrick的机器上运行,并且有一个解决方法。

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

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