Eclipse中的Groovy'def'关键字和范围问题

时间:2011-03-21 10:54:45

标签: eclipse groovy scope

我正在遵循一个groovy教程,并且有一个像这样的代码:

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

Eclipse在闭包定义行报告错误:

  

行断点:SimpleClosuresTest   [line:27]目前的范围已经   包含名称fruit的变量   @第27行,第14栏。

如果我从'def fruit'省略'def',那么Eclipse不会投诉并且代码运行正常。

有人可以解释两种情况下范围的变化吗?

感谢。

3 个答案:

答案 0 :(得分:3)

首先对groovy脚本进行一般性审查:

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

大致编译为:

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

在一个groovy脚本中(粗略地说,没有类声明的文件),为未定义的变量赋值被解释为字段赋值。

您的示例尝试使用名为fruit的参数定义闭包 如果您使用fruit关键字定义def,则会收到错误消息,因为该名称已被视为局部变量,并且您无法复制本地变量名称。
当您离开def关键字时,实际上是将值分配给为脚本生成的类的字段,因此可以将名称fruit重新定义为局部变量。

关于范围,它非常像java ...
在示例中,您可以看到x首先定义为字段,然后定义为run()方法的本地变量。这没有什么不对,你可以访问变量和字段 但是一旦定义了局部变量,就无法创建重复项。

编辑 -
在任何人弄错我之前必须添加这个:翻译不完全像这样(因此“大致”)。您可以为命令行脚本args添加一个值而不是字段,而非requestsessionresponse用于groovlet。 但这是一个更长的故事...
好的,如果你真的想知道再问一遍,我会更好地解释

编辑2 - 如果您需要更多信息,我就不能这样离开......

每个groovy脚本都有一个名为binding的字段,一个groovy.lang.Binding的实例或其中一个子类。
这个绑定基本上是一个地图,方法setVariablesetVariable 当您在脚本中分配值时忽略def关键字时实际调用方法setVariable,当您执行this.x之类的操作时,您调用getVariable方法。
这实际上是因为类groovy.lang.Script会覆盖方法getPropertysetProperty以首先调用这些方法。这就是他们表现得像田地的原因 您可能还注意到没有与这些变量关联的类型......那是因为我们只在绑定中处理Map
标准的groovy scrips是使用绑定实例创建的,args设置为参数数组 其他人,比如groovy.servlet.ServletBinding定义更多变量和行为,比如阻止某些变量的赋值,或者添加一个惰性初始化函数......

然后错误背后的真正原因是......如果未使用def关键字,fruits不是真正的变量。不过,我相信这种行为有点类似于一个领域。

抱歉这一切。 我对自己的过度简化感到不满:S

答案 1 :(得分:2)

该String水果不应与您的def水果同名。 (您首先定义一个列表,然后定义一个具有相同名称的字符串)

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

在第二种情况下,你用def a posteriori定义变量的类型,所以它可以工作但据我所知这不是一个好习惯。

我认为你甚至不需要写 - >。 groovy手册说“ - >令牌是可选的,如果您的Closure定义需要少于两个参数,则可以省略”,这就是这种情况。

答案 2 :(得分:0)

第二行

  

String fruit

再次使用相同的变量名'fruit'