case...when...else


case就類似其它語言(如C/C++、Java)經常會提供的switch..case,一個使用的例子如下:
# encoding: Big5
print "請輸入分數:"
case gets.to_i / 10
when 10, 9
puts "等級 A"
when 8
puts "等級 B"
when 7
puts "等級 C"
when 6
puts "等級 D"
else
puts "等級 E"
end

這個範例可以讓你輸入分數,經case...when比對後顯示對應的得分等級。與其它語言所提供的switch...case不同的是,case...when不需使用breakwhen比對成功並執行後,就自動離開case,不會再往下一個case進行比對,如果有多個情況符合時要執行同一運算,則使用逗號。case以外的比對可使用else

when比對成功時執行的程式碼若要撰寫在同一行,必須使用then。例如:
# encoding: Big5
print "請輸入分數:"
case gets.to_i / 10
when 10, 9 then puts "等級 A"
when 8 then puts "等級 B"
when 7 then puts "等級 C"
when 6 then puts "等級 D"
else puts "等級 E"
end

case...when有傳回值,每個when中最後一句程式碼執行的傳回值,就會是case...when的傳回值,所以上例可以改寫為以下(記得Ruby中要換行的部份,也可以使用分號):
# encoding: Big5
print "請輸入分數:"
puts case gets.to_i / 10
when 10, 9 ; "等級 A"
when 8 ; "等級 B"
when 7 ; "等級 C"
when 6 ; "等級 D"
else ; "等級 E"
end

case比對時,when的部份其實可以放任何物件,when會使用===方法,如果兩邊都是實例,預設實作會比較兩個變數是否參考同一實例,如果不是,會再呼叫==。如果左邊是類別而右邊是實例,===比較實例是否由該類別所生成。因此,重新定義==方法,就可以讓物件用於case比對。

case比對每次遇到when時,就會拿case右邊設定的物件,與when設定的物件進行===比對,若結果為true,表示比對成功,所以實際上完整寫法如下::
# encoding: Big5
print "請輸入分數:"
n = gets.to_i / 10
puts case n
when n === 10, n === 9 ; "等級 A"
when n === 8 ; "等級 B"
when n === 7 ; "等級 C"
when n === 6 ; "等級 D"
else ; "等級 E"
end

這段程式碼只是為了驗證先前說法,實際上不會故意這樣寫。不過這並不表示,case..when中的when只要是true或false的結果,所以你不可以這麼寫:
# encoding: Big5
print "請輸入分數:"
n = gets.to_i / 10

# 以下寫法是錯的
puts case n
when n == 10, n == 9 ; "等級 A"
when n == 8 ; "等級 B"
when n == 7 ; "等級 C"
when n == 6 ; "等級 D"
else ; "等級 E"
end

如果你真的要在when時撰寫true或false來決定是否執行when的區塊,case之後無須撰寫物件。例如:
# encoding: Big5
print "請輸入分數:"
n = gets.to_i / 10
puts case
when n == 10, n == 9 ; "等級 A"
when n == 8 ; "等級 B"
when n == 7 ; "等級 C"
when n == 6 ; "等級 D"
else ; "等級 E"
end

這也是為何,在
快速排 序法(三)中,Ruby版本的實現可以如下(模擬 Scala 中模式比對語法):
class Array
def comprehend(&block)
return self if block.nil?
self.collect(&block).compact
end
end

def quick(lst)
case
when lst.length <= 1
lst
when pivot = lst.shift
before = lst.comprehend { |i| i if i < pivot}
after = lst.comprehend { |i| i if i >= pivot}
quick(before) + [pivot] + quick(after)
end
end