天天看點

Ruby和Groovy的一個運作時差異點

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的不同行為,并在必要時加以改寫。