Ruby和Groovy是两种看上去很相似的编程语言,但由于运行时机制的不同,导致两种编程语言在block中的return语句处理有很大差别,具体原因在于:
- Ruby在语言设计上很大程度上参考了Smalltalk。在Smalltalk编程语言中,block可以直接返回到调用函数外层,这一语言特性称为non-local return。Ruby也有此特性。
- Groovy的运行时是基于JVM的,在JVM规范中不存在non-local return这样的特性,于是,在block中使用return语句的行为就和Ruby不同。
在下面这段Ruby代码中,由于non-local return特性,bar函数里的block中的return语句会导致bar函数返回:
def foo
[1,2,3].map{ |a| 2*a }
end
def bar
[1,2,3].map{ |a| return 2*a }
end
p foo #[2, 4, 6]
p bar #2
同样的Groovy代码,在block中使用return语句不会对运行结果产生影响, foo和bar这两个函数的行为完全一样:
def foo() {
[1, 2, 3].collect { it * 2 }
}
def bar() {
[1, 2, 3].collect { return it * 2 }
}
println(foo()) //[2, 4, 6]
println(bar()) //[2, 4, 6]
再看一个更真实的例子:
Ruby代码实现的一个判重逻辑:
def in_list(l, e)
l.each do |x|
if x == e then
return true
end
end
return false
end
p in_list([1, 2], 1) #true
同样写法的Groovy代码的运行结果是不对的:
def in_list(l, e) {
l.each {
if (it == e) {
return true
}
}
return false
}
println(in_list([1, 2], 1)) #false
必须改写成:
def in_list(l, e) {
for (it in l) {
if (it == e) {
return true
}
}
return false
}
println(in_list([1, 2], 1)) #true
综上,当同时使用这两种编程编程语言编码时必须加倍小心,特别要注意分辨带return语句的block的不同行为,并在必要时加以改写。