Rubyの例外処理について基本と注意点をまとめた。
例外処理の文法
Rubyで例外処理を行うのはbegin
-rescue
-else
-ensure
-end
構文である。JavaやC++でいうtry
-catch
と使い方は概ね同じである。以下にリファレンスマニュアから引用して文法を示す。
begin
式..
[rescue [error_type,..] [=> evar] [then]
式..]..
[else
式..]
[ensure
式..]
end
begin
節の処理で例外が発生した場合はrescue
節が評価され、例外が発生しなかった場合はelse
節が評価される。例外の発生有無に関わらず、ensure
節はbegin
節の実行後に必ず評価される。
例外処理の注意点
rescue
節はerror_type
を指定することで、発生する例外と対応させて複数記述することができる。error_type
を省略した時は、Exception
ではなくStandardError
を指定したのと同じになることに注意しよう。以下の2つは同一である。
begin
# do something
rescue
# recover
end
begin
# do something
rescue StandardError
# recover
end
error_type
に明示的にException
を指定することもできるが、普通はException
を捕捉するようにしてはいけない。この説明は例外の階層で後述する。
よりエレガントな例外処理
例外処理を簡潔に記述するためにrescue
修飾子がある。この修飾子は以下の文法で、式1
で例外が発生したときに、式2
を評価する。
式1 rescue 式2
rescue
修飾子は以下のようなbegin
-rescue
-end
と同等であり、省略形と言える。
begin
式1
rescue
式2
end
もう1点、リファレンスマニュアルには以下の記載がある。さらっと書いてあるが重要なことだ。 メソッド定義の中ではbegin
-end
を省略することができるというのだ。
クラス/メソッドの定義/クラス定義、クラス/メソッドの定義/モジュール定義、クラス/メソッドの定義/メソッド定義 などの定義文では、それぞれ begin なしで rescue, ensure 節を定義でき、これにより例外を処理することが できます。
つまり以下のような例外処理は、
def foo
begin
# do someting
rescue
# recover
end
end
冗長なbegin
-end
を省略して、次のように書けるというわけだ。
def foo
# do someting
rescue
# recover
end
例外の階層
以下にRuby 1.9.3の組み込み例外クラスの一覧を示す。(抽出したのはExceptionの子クラスと孫クラスまで)
- Exception
- fatal
- NoMemoryError
- ScriptError
- NotImplementedError
- LoadError
- SyntaxError
- SecurityError
- SignalException
- Interrupt
- StandardError
- ArgumentError
- EncodingError
- FiberError
- IOError
- IndexError
- LocalJumpError
- Math::DomainError
- NameError
- RangeError
- RegexpError
- RuntimeError
- SystemCallError
- ThreadError
- TypeError
- ZeroDivisionError
- SystemExit
- SystemStackError
一般的な例外はすべてStandardError
のサブクラスとなっていることがわかる。
またStandardError
以外のException
のサブクラスには、メモリ不足で発生するNoMemoryError
や、シグナルを受信した際に発生するSignalException
(Interrupt
)など、即座にスクリプトを中止すべき例外が並んでいることもわかる。
この例外の階層こそ、注意点で述べたようにRubyがrescue
で捕捉するデフォルトの例外がStandardError
であり、安易にException
を捕捉してはならない理由である。
基本的には、StandardErro
以外の例外が発生したら、即座に処理を終了すべきなのである。