Groovy:“def x = 0”中“def”的用途是什么?

在下面的一段代码(取自Groovy用户指南 )中,为什么在关键字def前加赋值?

def x = 0 def y = 5 while ( y-- > 0 ) { println "" + x + " " + y x++ } assert x == 5 

def关键字可以被删除,这个片段会产生相同的结果。 那么关键字def有什么作用呢?

这是基本脚本的语法糖。 省略“def”关键字将variables放在当前脚本的绑定中,groovy将它视为一个全局范围的variables:

 x = 1 assert x == 1 assert this.binding.getVariable("x") == 1 

使用def关键字不会将variables放在脚本绑定中:

 def y = 2 assert y == 2 try { this.binding.getVariable("y") } catch (groovy.lang.MissingPropertyException e) { println "error caught" } 

打印:“发现错误”

在较大的程序中使用def关键字非常重要,因为它有助于定义可以findvariables的范围,并且可以帮助保持封装。

如果在脚本中定义了一个方法,它将无法访问在主脚本主体中使用“def”创build的variables,因为它们不在范围内:

  x = 1 def y = 2 public bar() { assert x == 1 try { assert y == 2 } catch (groovy.lang.MissingPropertyException e) { println "error caught" } } bar() 

打印“错误捕获”

“y”variables不在函数内。 “x”在范围内,因为groovy会检查variables当前脚本的绑定。 正如我刚才所说,这只是简单的语法糖,可以使快速和肮脏的脚本更快地输出(通常是一行)。

在较大的脚本中,好的做法是始终使用“def”关键字,这样就不会遇到奇怪的范围问题,也不会干扰您不想要的variables。

特德的答案是非常好的脚本; 本的答案是类的标准。

就像Ben说的那样,把它想象成“Object” – 但是它更酷,因为它不会限制你使用Object方法。 这对import产生了很好的影响。

例如在这个片段中,我必须导入FileChannel

 // Groovy imports java.io.* and java.util.* automatically // but not java.nio.* import java.nio.channels.* class Foo { public void bar() { FileChannel channel = new FileInputStream('Test.groovy').getChannel() println channel.toString() } } new Foo().bar() 

例如但是在这里,只要所有东西都在类path上,我就可以“永远”

 // Groovy imports java.io.* and java.util.* automatically // but not java.nio.* class Foo { public void bar() { def channel = new FileInputStream('Test.groovy').getChannel() println channel.toString() } } new Foo().bar() 

根据这个页面 , def是一个types名称的替代品,可以简单地被认为是Object的别名(即表示你不关心types)。

就这个单一的剧本而言,没有实际的区别。

但是,使用关键字“def”定义的variables被视为本地variables,即本地脚本。 第一次使用时,前面没有“def”的variables存储在一个所谓的绑定中。 您可以将绑定看作variables和闭包的通用存储区域,这些variables和闭包需要在“之间”脚本之间可用。

因此,如果您有两个脚本并使用相同的GroovyShell执行它们,则第二个脚本将能够获取第一个脚本中未设置“def”的所有variables。

最重要的是,你们真的不是每个人都想不小心创造一个variables。 在脚本中,在一个任务上创buildvariables是可以的,但是在生产代码中,这是你遇到的最大的弊端之一。 我不会考虑任何允许此构造在生产代码中可用的语言。

我曾经在不止一个使用过visual basic的地方进行了访问,他们问了“VB文件中的第一行是什么”这个问题,如果你没有回答“OPTION EXPLICIT”,采访就停在那里。 (OPTION EXPLICIT不允许通过VB中的赋值创buildvariables,并强制显式的“暗淡”)

这是一个很糟糕的例子。 这将运行(没有失败断言),如果您复制下面的代码并将其粘贴到一个groovy脚本:

 bill = 7 bi1l = bill + 3 assert bill == 7 

它也消除了一些编译器帮助你重构的能力。 例如,如果您重命名第一次使用variables的地方,编译器如何知道是否第二次使用(赋值)现在是错误而不是新variables?

像这样的垃圾太危险了。 即使在你的生活中只有你一次,它仍然会花费更多的时间,而不是在整个你的carreer中明确地声明variables数千次。 它也清楚地知道它在哪里被删除,你不必猜测。

在脚本中它是相当好的,因为脚本的作用域是有限的,它们不会像重写一样被重用和维护,但是允许在赋值时创build的语言还没有准备好用于生产。

事实上,我认为它会有相同的performance

Groovy中的variables仍然需要声明,而不是TYPED声明,因为右侧通常包含Groovyinputvariables的足够信息。

当我尝试使用我没有用def或者types声明的variables时,我得到一个错误“没有这样的属性”,因为它假定我使用了包含代码的类的成员。