我正在遵循一个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不会投诉并且代码运行正常。
有人可以解释两种情况下范围的变化吗?
感谢。
答案 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
添加一个值而不是字段,而非request
,session
或response
用于groovlet。
但这是一个更长的故事...
好的,如果你真的想知道再问一遍,我会更好地解释
编辑2 - 如果您需要更多信息,我就不能这样离开......
每个groovy脚本都有一个名为binding
的字段,一个groovy.lang.Binding
的实例或其中一个子类。
这个绑定基本上是一个地图,方法setVariable
和setVariable
当您在脚本中分配值时忽略def
关键字时实际调用方法setVariable
,当您执行this.x
之类的操作时,您调用getVariable
方法。
这实际上是因为类groovy.lang.Script
会覆盖方法getProperty
和setProperty
以首先调用这些方法。这就是他们表现得像田地的原因
您可能还注意到没有与这些变量关联的类型......那是因为我们只在绑定中处理Map
。
标准的groovy scrips是使用绑定实例创建的,args
设置为参数数组
其他人,比如groovy.servlet.ServletBinding
定义更多变量和行为,比如阻止某些变量的赋值,或者添加一个惰性初始化函数......
然后错误背后的真正原因是......如果未使用def
关键字,fruits
不是真正的变量。不过,我相信这种行为有点类似于一个领域。
答案 1 :(得分:2)
该String水果不应与您的def水果同名。 (您首先定义一个列表,然后定义一个具有相同名称的字符串)
def likeIt = { String fruit -> println "I like " + fruit + "s" }
在第二种情况下,你用def a posteriori定义变量的类型,所以它可以工作但据我所知这不是一个好习惯。
我认为你甚至不需要写 - >。 groovy手册说“ - >令牌是可选的,如果您的Closure定义需要少于两个参数,则可以省略”,这就是这种情况。
答案 2 :(得分:0)
第二行
String fruit
再次使用相同的变量名'fruit'