在groovy中的try块中返回的奇怪行为

时间:2014-05-20 15:48:29

标签: groovy groovy-console

拿这个片段:

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并尝试返回asdf,但在将set line返回到asdf之前不应该影响返回值。

2)由于第二个输出是zxcv,我们必须接受行line = "zxcv"正在执行。那么,为什么它会被设置为asdf以获得第三个输出?

3)取消注释line = "qwer"行会产生如下输出:

asdf
qwer
asdf

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

使用Groovy 2.2.2

编辑: AHA!我从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

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

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。或者其他的东西。知道这只是一个工具的问题,而不是语言让我不想从这种语言开始尖叫,我才开始真正享受。

2 个答案:

答案 0 :(得分:3)

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

基本上你应该删除第一行中的def以获得.Net结果。

但是我必须把自己和Nathan放在一起,你的程序通常不会产生你所说的输出。这是因为如果您已阅读链接页面,则会知道line中的foo()引用了绑定,而linefoo()是本地的MissingPropertyException变量,与绑定无关。因此,预期的结果是在执行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 。为了让事情变得更容易,我在这里再次完整的程序:

foo()

因此,鉴于此更正的计划,我可以回答您的问题:

  1. 打印zxcv的值会产生123,因为这是输入函数时line的值。如果您更改要使用的第一行,例如123,则会zxcv而不是line = "zxcv"
  2. 确实执行了行foobar并更改了绑定中存储的内容。但它并没有改变方法返回的内容,所以即使你改变了它以将println分配给line也会得到相同的结果。由于第三个foo()正在读取局部变量而不是绑定,因此还解释了line = "qwer"缺少的可见效果。
  3. 取消注释原始程序中的MissingPropertyException将确保您在绑定中有某些内容,因此您将无法获得foo()。但finally仍然会在执行qwer块之前返回绑定中的内容,因此会返回{{1}}。

答案 1 :(得分:1)

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

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

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