开发者

Groovy 'def' keyword and scope problem in Eclipse

I'm following a groovy tutorial and there is a code like this:

def fruit = ["apple", "orange" , "pear"]    //list
def likeIt = { String fruit -> println "I like " + fruit + "s" }    //closure
fruit.each(likeIt)

Eclipse reports an error at closure definition line:

Line breakpoint:SimpleClosuresTest [line: 27] The current scope already contains a variable of the na开发者_开发问答me fruit @ line 27, column 14.

If i omit 'def' from 'def fruit' Eclipse doesn't complaint and code runs fine.

Could someone explain what is going on with the scopes in both cases?

Thanks.


first a general review of a groovy script:

// file: SomeScript.groovy
x = 1
def x = 2
println x
println this.x

is roughly compiled as:

class SomeScript extends groovy.lang.Script {
  def x
  def run() {
    x = 1
    def x = 2
    println x // 2
    println this.x // 1
  }
}

in a groovy script (roughly speaking, a file without the class declaration), assigning a value to an undefined variable is interpreted as a field assignment.

your example tries to defines a closure with a parameter named fruit.
if you defined fruit with the def keyword you get an error message because the name is already taken as a local variable, and you can't duplicate a local variable name.
when you leave the def keyword out, you are actually assigning the value to a field of the class generated for the script, and thus the name fruit can be redefined as a local variable.

regarding scopes, it's pretty much like java...
in the example, you can see x is defined first as a field and then as a variable local to the run() method. there's nothing wrong with that and you can access both the variable and the field.
but once you define a local variable, you cannot create duplicates.

edit --
had to add this before anyone gets me wrong: the translation is not exactly like this (thus the "roughly"). Instead of a field you add a value to the binding of the script, quite like args for commandline scripts or request, session or response for groovlets.
but that is much a longer story...
ok if you really want to know just ask again and i'll explain it better

edit 2 -- i just can't leave it like this, if you ever need more info...

every groovy script has a field named binding, an instance of groovy.lang.Binding or one of its a subclasses.
this binding is basically a map, with methods setVariable and setVariable.
when you omit the def keyword when assigning a value in a script you are actually calling the method setVariable, and when you do something like this.x you are calling the getVariable method.
this is actually because class groovy.lang.Script overrides the methods getProperty and setProperty to call those methods first. that's the reason they behave like fields.
you might have also noticed that there is no type associated to those variables... that's because we are dealing with just a Map inside the binding.
standard groovy scrips are created with an instance of a binding with the args set to the array of parameters.
others, like groovy.servlet.ServletBinding define more variables and behavior, like block the assignment of certain variables, or adding a lazy initialization capabilities...

then the real reason behind the error is... if the def keyword is not used, fruits is not a real variable. still, i believe the behavior is somewhat analog to a field.

sorry about all that. i was not satisfied with my own oversimplification :S


That String fruit shouldn't be having the same name as your def fruit. (you are defining first a list and then a string with the same name)

def likeIt = { String fruit -> println "I like " + fruit + "s" }    

In the second case you are defining the type of the variable with def a posteriori, so it works but it is not a good practice as far as I know.

I think that you don't even need to write ->. The groovy manual says that "The -> token is optional and may be omitted if your Closure definition takes fewer than two parameters", which is the case here.


Second line

String fruit

the same variable name 'fruit' is being used again

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜