程式扎記: [ Ruby Gossip ] Basic : 流程控制 - begin...rescue...ensure

標籤

2014年10月21日 星期二

[ Ruby Gossip ] Basic : 流程控制 - begin...rescue...ensure

Source From Here 
Preface 
以下這個程式,預期使用者要輸入整數: 
  1. # encoding: Big5  
  2. print "輸入整數:"  
  3. input = gets.to_i  
  4. puts "#{input} 為 %s" % (input % 2 == 0 ? "偶數" : "奇數")  
如果使用者輸入的不是整數,就會出現錯誤: 
 

begin...rescue...ensure 
在 Ruby 中程式若發生錯誤,會丟出例外,例外為 Exception 或其子類別實例,以上例而言就是引發(RaiseArgumentError 物件,如果程式沒有處理例外而丟出至執行環境,則會顯示例外追蹤(Trace back)並中斷程式。如果你想要處理例外,則可以使用begin...rescue 語句。例如: 
  1. # encoding: Big5  
  2. begin  
  3.     print "輸入整數:"  
  4.     input = Integer(gets)  
  5.     puts "#{input} 為 %s" % (input % 2 == 0 ? "偶數" : "奇數")  
  6. rescue ArgumentError  
  7.     puts "請輸入阿拉伯數字"  
  8. end  
如果使用者輸入錯誤,引發的ArgumentError物件會被rescue比對型態是否相同,如果相同則執行對應的區塊。以上例而言,如果使用者輸入錯誤,就會顯示較友善的提示訊息(而不是丟個使用者看不懂的追蹤訊息). begin..rescue 的 rescue 可以指定多個物件,也可以有多個rescue,如果沒有指定 rescue 後的物件型態,則表示捕捉所有引發的物件。舉例來說,上例中若使用者於輸入時輸入 Ctrl+Z,在Windows環境下會引發 TypeError,若輸入 Ctrl+C,則會引發Interrupt。下例中處理這些可能的狀況: 
  1. # encoding: Big5  
  2. begin  
  3.     print "輸入整數:"  
  4.     input = Integer(gets)  
  5.     puts "#{input} 為 %s" % (input % 2 == 0 ? "偶數" : "奇數")  
  6. rescue ArgumentError  
  7.     puts "請輸入阿拉伯數字"  
  8. rescue TypeError, Interrupt  
  9.     puts "使用者中斷程式"  
  10. rescue  
  11.     puts "不明的程式中斷"  
  12. end  
如果沒有指定 rescue 後的物件型態,則表示捕捉所有引發的物件,所以這樣的rescue必須置於最後。begin..rescue 還可以搭配 ensure,一但設置,無論有無引發物件,ensure 區塊一定會執行,這通常用來作為關閉若干資源的區塊,例如關閉檔案: 
  1. # encoding: Big5  
  2. print "檔案名稱:"  
  3. name = gets.chomp  
  4. file = open(name, "r")  
  5. begin  
  6.     file.each do |line|  
  7.         print line  
  8.     end  
  9. rescue  
  10.     print "讀取檔案發生錯誤"  
  11. ensure  
  12.     file.close  
  13. end  
可以使用 raise 自行引發例外。例如: 
 

可以在 rescue 捕捉到例外後,將例外物件指定給變數。例如: 
 

在使用 raise 引發錯誤時,可以附上訊息,若 rescue 捕捉到例外物件時,可以使用 message 方法取得訊息: 
 

這相當於: 
 

也可以使用例外物件的 backtrace 取得例外追蹤訊息,訊息會以陣列型態傳回。例如: 
  1. # encoding: Big5  
  2. begin  
  3.     print "輸入整數:"  
  4.     input = Integer(gets)  
  5.     puts "#{input} 為 %s" % (input % 2 == 0 ? "偶數" : "奇數")  
  6. rescue ArgumentError => e  
  7.     puts "請輸入阿拉伯數字"  
  8.     print e.backtrace  
  9. end  
輸入整數:ten
請輸入阿拉伯數字
["main.rb:4:in `Integer'", "main.rb:4:in `
'"]

在定義方法時,若 begin...end 邊界實際上就是方法邊界,可只撰寫 rescue。例如下面這個 odd_even? 方法: 
  1. # encoding: Big5  
  2. def odd_even?  
  3.     begin  
  4.         print "輸入整數:"  
  5.         input = Integer(gets)  
  6.         puts "#{input} 為 %s" % (input % 2 == 0 ? "偶數" : "奇數")  
  7.     rescue ArgumentError => e  
  8.         puts "請輸入阿拉伯數字"  
  9.         print e.backtrace  
  10.     end  
  11. end  
  12. odd_even?  
可以只寫為: 
  1. # encoding: Big5  
  2. def odd_even?  
  3.     print "輸入整數:"  
  4.     input = Integer(gets)  
  5.     puts "#{input} 為 %s" % (input % 2 == 0 ? "偶數" : "奇數")  
  6.     rescue ArgumentError => e  
  7.         puts "請輸入阿拉伯數字"  
  8.         print e.backtrace  
  9. end  
  10. odd_even?  
Supplement 
Ruby 使用手冊 - 例外處理 之 救援 (rescue) 
Ruby 使用手冊 - 例外處理 之 確認 (ensure)

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!