2014年10月20日 星期一

[ Ruby Gossip ] Basic : 流程控制 - case...when...else

Source From Here 
Preface 
case 就類似其它語言(如C/C++、Java)經常會提供的 switch..case,一個使用的例子如下: 
  1. # encoding: Big5  
  2. print "請輸入分數:"  
  3. case gets.to_i / 10  
  4.     when 109  
  5.         puts "等級 A"  
  6.     when 8  
  7.         puts "等級 B"  
  8.     when 7  
  9.         puts "等級 C"  
  10.     when 6  
  11.         puts "等級 D"  
  12.     else  
  13.         puts "等級 E"  
  14. end  
這個範例可以讓你輸入分數,經case...when比對後顯示對應的得分等級。與其它語言所提供的switch...case不同的是,case...when不需使用break,when比對成功並執行後,就自動離開case,不會再往下一個case進行比對,如果有多個情況符合時要執行同一運算,則使用逗號。case以外的比對可使用else。 

case...when...else 
在 when 比對成功時執行的程式碼若要撰寫在同一行,必須使用 then。例如: 
  1. # encoding: Big5  
  2. print "請輸入分數:"  
  3. case gets.to_i / 10  
  4.     when 109 then puts "等級 A"  
  5.     when 8     then puts "等級 B"  
  6.     when 7     then puts "等級 C"  
  7.     when 6     then puts "等級 D"  
  8.     else            puts "等級 E"  
  9. end  
case...when 有傳回值,每個 when 中最後一句程式碼執行的傳回值,就會是 case...when 的傳回值,所以上例可以改寫為以下(記得Ruby中要換行的部份,也可以使用分號): 
  1. # encoding: Big5  
  2. print "請輸入分數:"  
  3. puts case gets.to_i / 10  
  4.          when 109 ; "等級 A"  
  5.          when 8     ; "等級 B"  
  6.          when 7     ; "等級 C"  
  7.          when 6     ; "等級 D"  
  8.          else       ; "等級 E"  
  9.      end  
case 比對時,when 的部份其實可以放任何物件,when會使用 === 方法,如果兩邊都是實例,預設實作會比較兩個變數是否參考同一實例,如果不是,會再呼叫 ==。如果左邊是類別而右邊是實例,=== 比較實例是否由該類別所生成。因此,重新定義 == 方法,就可以讓物件用於 case 比對。 

case 比對每次遇到 when 時,就會拿 case 右邊設定的物件,與 when 設定的物件進行 === 比對,若結果為 true,表示比對成功,所以實際上完整寫法如下: 
  1. # encoding: Big5  
  2. print "請輸入分數:"  
  3. n = gets.to_i / 10  
  4. puts case n  
  5.          when n === 10, n === 9 ; "等級 A"  
  6.          when n === 8           ; "等級 B"  
  7.          when n === 7           ; "等級 C"  
  8.          when n === 6           ; "等級 D"  
  9.          else                   ; "等級 E"  
  10.      end  
這段程式碼只是為了驗證先前說法,實際上不會故意這樣寫。不過這並不表示,case..when 中的 when 只要是 true 或 false 的結果,所以你不可以這麼寫: 
  1. # encoding: Big5  
  2. print "請輸入分數:"  
  3. n = gets.to_i / 10  
  4.   
  5. # 以下寫法是錯的  
  6. puts case n  
  7.          when n == 10, n == 9  ; "等級 A"  
  8.          when n == 8           ; "等級 B"  
  9.          when n == 7           ; "等級 C"  
  10.          when n == 6           ; "等級 D"  
  11.          else                  ; "等級 E"  
  12.      end  
如果你真的要在 when 時撰寫 true 或 false 來決定是否執行 when 的區塊,case 之後無須撰寫物件。例如: 
  1. # encoding: Big5  
  2. print "請輸入分數:"  
  3. n = gets.to_i / 10  
  4. puts case  
  5.          when n == 10, n == 9  ; "等級 A"  
  6.          when n == 8           ; "等級 B"  
  7.          when n == 7           ; "等級 C"  
  8.          when n == 6           ; "等級 D"  
  9.          else                  ; "等級 E"  
  10.      end  
這也是為何,在 快速排序法(三)中,Ruby版本的實現可以如下(模擬 Scala 中模式比對語法): 
  1. class Array  
  2.     def comprehend(&block)  
  3.         return self if block.nil?  
  4.         self.collect(&block).compact  
  5.     end  
  6. end  
  7.   
  8. def quick(lst)  
  9.     case  
  10.         when lst.length <= 1  
  11.             return lst  
  12.         when pivot = lst.shift  
  13.             printf "Pivot=%s:\n", pivot  
  14.             before = lst.comprehend { |i| i if i < pivot}  
  15.             printf "\tBefore=%s\n", before  
  16.             after = lst.comprehend { |i| i if i >= pivot}  
  17.             printf "\tAfter=%s\n", after  
  18.             merge=quick(before) + [pivot] + quick(after)  
  19.             printf "\tMerge=%s\n", merge  
  20.             return merge  
  21.         else  
  22.             printf "\t[Error] Unknown case!\n"  
  23.     end  
  24. end  
  25.   
  26. ary = [1,4,5,3,8,9,7,2,6]  
  27. printf "ary=#{ary} (%s)\n", ary.class  
  28. print "Quick sort...\n"  
  29. ary=quick(ary)  
執行結果: 
 

補充說明: 
Array.collect: Invokes the given block once for each element of self. 
Array.compact: Returns a copy of self with all nil elements removed.

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...