Ruby 使用手冊

例外處理:救援 Exception processing: rescue

執行中的程式可能出現意料之外的問題。例如:發現要讀取的檔案不存在;儲存資料時發現磁碟已滿;輸入不合適的內容。

ruby> file = open("some_file")
ERR: (eval):1:in `open': No such file or directory - some_file

穩健的程式能夠快速發現問題,並完善解決, 要達成這樣的目標總是讓人沮喪。C 程式員需要檢查任何可能出錯的系統呼叫 (system call),並立即決定應對措施:

FILE *file = fopen("some_file", "r");
if (file == NULL) {
  fprintf( stderr, "File doesn't exist.\n" );
  exit(1);
}
bytes_read = fread( buf, 1, bytes_desired, file );
if (bytes_read != bytes_desired ) {
  /* do more error handling here ... */
}
...

這種工作讓人感到厭煩,程式員就會開始不小心,甚至不檢查,最終造成程式未能完善處理例外。另一方面,做好這類檢查工作,會讓程式變得難以看懂,因為太多錯誤處理會讓程式碼顯得雜亂。

Ruby 就如許多現代語言一樣,能以區隔的 (compartmentalized) 方式處理例外的程式碼區塊,效果出眾而且不會對閱讀程式碼造成困難。標示有 begin 的程式碼區塊執行後若遇到例外,就將控制轉移至標示有 rescue 的錯誤處理程式碼區塊 (block of error handling code)。若沒有出現例外,就不會使用 rescue 程式碼。以下方法會傳回文字檔的第一行,若沒有例外的話則傳回 nil

def first_line( filename )
  begin
    file = open("some_file")
    info = file.gets
    file.close
    info  # 最後計算的內容為傳回值
  rescue
    nil   # 無法讀取檔案?那就不傳回字串
  end
end

有時候,我們需要能夠變通地處理問題。例如:如果無法找到需要的檔案,可嘗試使用標準輸入 (standard input):

begin
  file = open("some_file")
rescue
  file = STDIN
end

begin
  # ... 處理輸入 ...
rescue
  # ... 並在此處理其他例外。
end

retry 可用於 rescue 程式碼,以重新開始 begin 程式碼。現在把剛才的例子編寫得精簡一點吧:

fname = "some_file"
begin
  file = open(fname)
  # ... 處理輸入 ...
rescue
  fname = "STDIN"
  retry
end

但是,這裡有個錯誤, 一個不存在的檔案會讓這個程式碼無限迴圈。使用 retry 處理例外時,一定要注意這種陷阱。

在所有的 Ruby 函式庫中,如果出現例外錯誤,就會喚起 (raise) 例外。你也可以在自己的程式碼中喚起例外。若要喚起例外,可以使用 raise。這只需要一個引數,即描述該例外的字串。可選擇使用甚麼引數,但不得省略, 之後可使用特別的全域變數 $! 存取。

ruby> raise "test error"
   test error
ruby> begin
    |   raise "test2"
    | rescue
    |   puts "An error occurred: #{$!}"
    | end
An error occurred: test2
   nil

Copyright (c) 2005-2008 Mark Slagell,中文翻譯 Ruby Taiwan 社群

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.

A copy of the license is included in the section entitled "GNU Free Documentation License."