首先对一个 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 的参数定义闭包。
如果您使用 def 关键字定义了 fruit,则会收到一条错误消息,因为该名称已被视为局部变量,并且您不能复制局部变量名称。
当您离开 def 关键字时,您实际上是将值分配给为脚本生成的类的字段,因此名称 fruit 可以重新定义为局部变量。
关于作用域,它很像 java...
在示例中,您可以看到 x 首先定义为字段,然后定义为 run() 方法的局部变量。这没有什么问题,您可以同时访问变量和字段。
但是一旦你定义了一个局部变量,你就不能创建重复了。
编辑 --
必须在有人误会我之前添加这个:翻译并不完全像这样(因此是“大致”)。您将值添加到脚本的绑定中,而不是字段,就像 args 用于命令行脚本或 request、session 或 response 用于 groovlets。
但这是一个更长的故事......
好的,如果您真的想知道,请再问,我会解释得更好
编辑 2 --
如果您需要更多信息,我不能就这样离开……
每个 groovy 脚本都有一个名为 binding 的字段、groovy.lang.Binding 的实例或其子类之一。
这个绑定基本上是一个映射,带有方法setVariable 和setVariable。
当您在脚本中分配值时省略 def 关键字时,您实际上是在调用 setVariable 方法,而当您执行 this.x 之类的操作时,您正在调用 getVariable 方法。
这实际上是因为类groovy.lang.Script 覆盖了方法getProperty 和setProperty 以首先调用这些方法。这就是它们表现得像字段的原因。
您可能还注意到,没有与这些变量关联的类型...那是因为我们在绑定中只处理 Map。
标准 groovy 脚本是使用绑定实例创建的,其中 args 设置为参数数组。
其他的,比如groovy.servlet.ServletBinding 定义了更多的变量和行为,比如阻止某些变量的赋值,或者添加一个惰性初始化能力......
那么错误背后的真正原因是......如果没有使用def关键字,fruits不是一个真正的变量。尽管如此,我相信这种行为在某种程度上类似于一个领域。
对这一切感到抱歉。
我对自己的过度简化并不满意:S