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

时间:2008-10-08 17:59:15

标签: groovy

在下面的一段代码中(取自Groovy Semantics Manual page),为什么要在作业前加上关键字def

def x = 0
def y = 5

while ( y-- > 0 ) {
    println "" + x + " " + y
    x++
}

assert x == 5

可以删除def关键字,此代码段会生成相同的结果。那么关键字def效果是什么?

6 个答案:

答案 0 :(得分:261)

它是基本脚本的语法糖。省略“def”关键字会将变量放在当前脚本的绑定中,而groovy会将其(大部分)视为全局范围的变量:

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

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

def y = 2

assert y == 2

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

打印:“错误捕获”

在较大的程序中使用def关键字很重要,因为它有助于定义可以找到变量的范围,并有助于保留封装。

如果在脚本中定义一个方法,它将无法访问在主脚本正文中使用“def”创建的变量,因为它们不在范围内:

 x = 1
 def y = 2


public bar() {
    assert x == 1

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

bar()

打印“错误捕获”

“y”变量不在函数内的范围内。 “x”在范围内,因为groovy将检查变量的当前脚本的绑定。正如我之前所说的,这只是一种语法糖,可以更快地输出快速和脏的脚本(通常是一个衬里)。

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

答案 1 :(得分:35)

Ted's answer非常适合脚本; Ben's answer是课程的标准。

正如Ben所说,将其视为“对象” - 但它更酷,因为它不会限制你使用Object方法。这对进口产生了很好的影响。

e.g。在这个片段中,我必须导入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()

e.g。但是在这里,只要一切都在类路径上,我就可以“甩掉它”

// 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()

答案 2 :(得分:29)

根据此pagedef是类型名称的替代品,可以简单地将其视为Object的别名(即表示您不关心类型)。

答案 3 :(得分:12)

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

但是,使用关键字“def”定义的变量被视为局部变量,即本地脚本的本地变量。在它们前面没有“def”的变量在第一次使用时存储在所谓的绑定中。您可以将绑定视为需要在“脚本之间”可用的变量和闭包的一般存储区域。

因此,如果你有两个脚本并使用相同的GroovyShell执行它们,那么第二个脚本将能够获得在第一个脚本中设置的所有变量而没有“def”。

答案 4 :(得分:7)

最重要的是,你真的不是每个人都想要偶然创建一个变量。在脚本中可以在赋值中创建变量,但在生产代码中,它是您可能遇到的最大的弊端之一。我不会考虑任何允许此构造在生产代码中可用的语言。

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

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

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

它还删除了一些编译器帮助您重构的能力。例如,如果您重命名该位置,则首先使用该变量,编译器如何知道第二次使用(赋值)现在是错误而不是新变量?

像这样的废话太危险了。即使它只是你生命中的一次,它仍然会花费更多的时间,而不是在整个carreer中明确地声明变量数千次。它也变得清晰,只要它被推迟,你不必猜测。

在脚本中它是相当不错的,因为脚本的范围是有限的,并且它们不会被重写而重复使用和维护,但是允许在分配时创建的语言还没有为生产做好准备。

答案 5 :(得分:5)

实际上,我认为它的行为会相同......

Groovy中的变量仍然需要声明,而不是TYPED声明,因为右侧通常包含足够的信息供Groovy键入变量。

当我尝试使用我没有使用def或类型声明的变量时,我收到错误“No such property”,因为它假设我正在使用包含代码的类的成员。 / p>