Groovy:what';“的目的是什么?”;def";在;def x=0“吗;?

Groovy:what';“的目的是什么?”;def";在;def x=0“吗;?,groovy,keyword,Groovy,Keyword,在下面的代码段中(取自),为什么要在分配前加上关键字def def x = 0 def y = 5 while ( y-- > 0 ) { println "" + x + " " + y x++ } assert x == 5 可以删除def关键字,此代码段将产生相同的结果。那么关键字def的效果是什么呢?事实上,我不认为它会有同样的表现 Groovy中的变量仍然需要声明,而不是类型化声明,因为右侧通常包含Groovy键入变量所需的足够信息 当我尝试使用一个我没有用

在下面的代码段中(取自),为什么要在分配前加上关键字
def

def x = 0
def y = 5

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

assert x == 5

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

事实上,我不认为它会有同样的表现

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


当我尝试使用一个我没有用def或type声明的变量时,我会得到一个错误“No-this-property”,因为它假设我使用的是包含代码的类的一个成员。

根据这一点,
def
是类型名称的替代,可以简单地看作是
对象的别名(即,表示您不关心类型)。

这是基本脚本的语法糖。省略“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”关键字,这样您就不会遇到奇怪的作用域问题或干扰您不打算使用的变量。

对于脚本来说是非常好的;对于类来说是标准的

正如Ben所说,将其视为“对象”——但它更酷,因为它不限制您使用对象方法。这对于导入有着简洁的含义

e、 在这个片段中,我必须导入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、 但是在这里,只要所有的东西都在类路径上,我就可以“随机应变”

// 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”定义的变量被视为局部变量,即此脚本的局部变量。前面没有“def”的变量在首次使用时存储在所谓的绑定中。您可以将绑定视为变量和闭包的一般存储区,这些变量和闭包需要在“两个”脚本之间可用

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

使用“def”的原因是告诉groovy您打算在此处创建一个变量。这一点很重要,因为您永远不希望意外地创建一个变量

这在脚本中是可以接受的(Groovy脚本和groovysh允许您这样做),但在生产代码中,这是您可能遇到的最大问题之一,这就是为什么您必须在所有实际Groovy代码(类内的任何代码)中用def定义变量的原因

下面是一个错误原因的示例。如果复制以下代码并将其粘贴到groovysh中,则会运行此操作(断言不会失败):

bill=7
bi1l=账单+3
断言账单==7
这类问题可能需要很多时间来发现和解决——即使它在你的一生中只咬了你一次,也要比在你的职业生涯中成千上万次明确地声明变量花费更多的时间。同时,它在声明的地方变得清晰,你不必猜测


在不重要的脚本/控制台输入(如groovy控制台)中,这在某种程度上是可以接受的,因为脚本的范围是有限的。我认为groovy允许您在脚本中这样做的唯一原因是像Ruby那样支持DSL(如果你问我,这是一个糟糕的权衡,但有些人喜欢DSL)

为什么允许您
新建FileInputStream('Test.groovy').getChannel()
不带导入?@AlexanderSuraphel“只要所有内容都在类路径上”