拿这个片段:
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
。或者其他的东西。知道这只是一个工具的问题,而不是语言让我不想从这种语言开始尖叫,我才开始真正享受。
答案 0 :(得分:3)
http://groovy.codehaus.org/Scoping+and+the+Semantics+of+%22def%22会解释一下情况。
基本上你应该删除第一行中的def
以获得.Net结果。
但是我必须把自己和Nathan放在一起,你的程序通常不会产生你所说的输出。这是因为如果您已阅读链接页面,则会知道line
中的foo()
引用了绑定,而line
外foo()
是本地的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()
因此,鉴于此更正的计划,我可以回答您的问题:
zxcv
的值会产生123
,因为这是输入函数时line的值。如果您更改要使用的第一行,例如123
,则会zxcv
而不是line = "zxcv"
。foobar
并更改了绑定中存储的内容。但它并没有改变方法返回的内容,所以即使你改变了它以将println
分配给line也会得到相同的结果。由于第三个foo()
正在读取局部变量而不是绑定,因此还解释了line = "qwer"
缺少的可见效果。MissingPropertyException
将确保您在绑定中有某些内容,因此您将无法获得foo()
。但finally
仍然会在执行qwer
块之前返回绑定中的内容,因此会返回{{1}}。答案 1 :(得分:1)
在Java(当然还有Groovy)中,finally块总是被执行,并且在方法结束之前执行,除非你调用System.exit()或者JVM崩溃。
在java中,字符串是不可变的,每次更改字符串值时都会创建一个新对象。
所以第一行是,第二行是指不同的对象。