简体   繁体   中英

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 ?

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. But that does not seem to be the case.

Why does s not keep the value which it was assigned from within the closure?

Solution / workaround

Passing s as argument to methodA() works. See lines commented with // 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-Eclipse plugin 2.8.0
  • 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.

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

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. However, it works from the console, it works on cfrick's machine and there is a workaround.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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