0

拿这个片段:

def line = "asdf"

String foo() {
  try {
     //line = "qwer"
     return line
  } finally {
     line = "zxcv"
  }
}

println line
println foo()
println line

来自 .NET 背景,我希望打印行能够产生

asdf
asdf
zxcv

然而,在 groovy 中,它会产生

asdf
zxcv
asdf

这在几个方面让我感到困惑。

1)为什么打印foo()生产的价值zxcv?我希望 return 语句能够评估line并尝试 return ,但在返回不应该影响返回值的asdfset line 之前。asdf

2)由于第二个输出是zxcv,我们必须接受该行line = "zxcv"正在执行。asdf那么,为什么要为第三个输出设置 BACK呢?

3)取消注释该line = "qwer"行产生的输出如下所示:

asdf
qwer
asdf

我认为这与任何一个模型都不一致。它看起来像一些奇怪的范围行为,但我无法弄清楚这里的规则是什么。

使用 Groovy 2.2.2

编辑:啊哈!我从 groovy 控制台运行它。看来,如果我将它包装在一个类中并运行它,程序会产生预期的输出,即:

class MyClass {
    def line = "asdf"

    String foo() {
      try {
         //line = "qwer"
         return line
      } finally {
         line = "zxcv"
      }
    }

    def printStuff() {    
      println line
      println foo()
      println line
    }
}

new MyClass().printStuff()

生产

asdf
asdf
zxcv

我还发现了Script -> Clear Script Context菜单选项。在清除脚本上下文后立即执行原始代码段时,控制台会抛出以下异常:

asdf
Exception thrown

groovy.lang.MissingPropertyException: No such property: line for class: ConsoleScript53

    at ConsoleScript53.foo(ConsoleScript53:6)

    at ConsoleScript53.run(ConsoleScript53:13)

随后的运行产生不正确的输出

asdf
zxcv
asdf

有了这些新信息,GroovyConsole 中似乎有一些奇怪的东西正在提升line到它的上下文中,并返回它而不是line在顶部声明。或者其他的东西。知道这只是工具而不是语言的问题,这让我不想从我刚刚开始真正喜欢的语言中尖叫。

4

2 回答 2

3

http://groovy.codehaus.org/Scoping+and+the+Semantics+of+%22def%22会稍微解释一下情况。

基本上,您应该删除def第一行中的 .Net 结果。

但是我必须把自己和 Nathan 放在一起,你的程序通常不会产生你所说的输出。那是因为如果你读过链接的页面,你就会知道,lineinfoo()引用的是绑定,而line外部foo()是一个局部变量,它与绑定无关。所以预期的结果是在执行时得到一个MissingPropertyExceptionfor return line。那是因为line在你第一次在那里写之前不存在绑定。

要生成您看到的输出,您需要实际添加一个

line = "zxcv"

之前def。这将确保line在绑定中存在。在将写入局部变量之后添加它def,您将不得不使用它binding.line。为了让事情变得更容易,我在这里再次给出完整的程序:

line = "zxcv"
def line = "asdf"

String foo() {
  try {
     //line = "qwer"
     return line
  } finally {
     line = "zxcv"
  }
}

println line
println foo()
println line

因此,鉴于这个更正的程序,我可以回答您的问题:

  1. 打印foo()产生的值,zxcv因为那是进入函数时 line 的值。例如,如果您将第一行更改为使用123,那么123您将得到的不是zxcv.
  2. 该行line = "zxcv"确实被执行并更改了绑定中存储的内容。但它不会改变方法将返回的内容,因此即使您将其更改为分配foobar给 line,您也会得到相同的结果。并且由于第三个是从局部变量而不是绑定中读取的,因此还解释println了缺少的可见效果。foo()
  3. 在原始程序中取消注释line = "qwer"将确保您在绑定中有一些东西,因此您不会得到MissingPropertyException. 但foo()仍会返回finally执行块之前绑定中的内容,因此您会qwer返回。
于 2014-05-22T14:53:12.487 回答
1

在 Java(当然还有 Groovy)中,finally 块总是被执行,并且在方法结束之前执行,除非您调用 System.exit() 或 JVM 崩溃。

在 java 中,字符串是不可变的,每次更改字符串值时都会创建一个新对象。

所以第一行是,第二行是指不同的对象。

于 2014-05-20T17:35:31.357 回答