Kamuycikap - SentenceDataBase

日々の勉強の記録を気分で書き綴るブログ

例外

多くのプログラミング言語と同様に、Rubyにも例外処理がサポートされている。
例外は、主にエラーを処理するための方法であり、旧来の手法に比べて多くの利点がある。
リターンコードを利用しなくてもよく、それをチェックすることで生じる複雑怪奇なプログラムになる可能性が劇的に少なくなる。
また、エラーを検出するコードと、エラーを処理するコードを分離することが可能。

raise文は例外を発生させる。
raiseは予約語ではなく、Kernelモジュールのメソッド。

raise                                         #例1
raise "Error Message."                        #例2
raise ArgumentError                           #例3
raise ArgumentError, "Error data."            #例4
raise ArgumentError.new("Error data.")        #例5
raise ArgumentError, "Error data.", caller[0] #例6

例1では直前の例外を再発生させる。
例2ではError Messageをメッセージとするデフォルトのエラー「RuntimeError」を発生させる。
例3ではArgumentErrorを発生させ、例4ではError dataをメッセージとする例3と同じエラーを発生させる。
例4と例5はまったく同じ動きをする。
例6は、filename:lineまたはfilename:line:in `method`形式のトレースバック情報が付加される。

Rubyでは、例外の処理にbegin-endブロックを利用する。
次に示すのは、実行するコードのみが入った最も単純な形式のbegin-endブロックである。

begin # 実際には何もしない
  # ...
end

当然ながら、このブロックはエラーに対して何の働きも無い。
ただし、ブロック内には1つ以上のrescue節を入れることができる。
beginとrescueの間にあるコードのどこかでエラーが発生すると、制御が直ちに適切なrescue節に渡される。

begin
  x = Math.sqrt(y/z)
  # ...
rescue ArgumentError
  print "Error taking square root.\n"
rescue ZeroDivisionError
  print "Attempted division by zero.\n"
end

これと同様の結果を生むコードが下記のコードである。

begin
  x = Math.sqrt(y/z)
  # ...
rescue => err
  print err, "\n"
end

こちらのコードでは、変数errを使って例外の値を格納している。
格納された値を出力すると値は何らかの意味のある文字列に変換されている。
エラータイプは指定されていないので、rescue節はほぼすべての種類のエラーを補足する。
rescue => err の表記では、=>記号の前にエラータイプを入れることも、いれないでおくことも可能。

エラータイプを指定した場合は、例外がどのエラータイプにも一致しない事がある。
そのような場合に備えて、次の様にすべてのrescue節の後ろに入れる事ができる。

begin
  # エラーを起こしやすいコード
rescue Type1
  # ...
rescue Type2
  # ...
else
  # 上記以外の例外
end

たいていは、何らかの回復処理を行うことになる。
その場合、次の様にキーワードretryをrescue節の中で利用し、beginブロックを起動しなおし、もう一度処理を実行してみる。

begin
  # エラーを起こしやすいコード
rescue
  # 回復を試みる...
  retry
end

さらに、begin-endブロックの後ろに後処理をするコードが必要になる場合がある。
その場合、次の様にensure節を指定する。

begin
  # エラーを起こしやすいコード
rescue
  # 例外処理...
ensure
  # ここは常に処理されるコード
end

ensure節のコードは、begin-endブロックが終了する前に必ず実行される。
これは例外が発生したかどうかとは無関係の処理となる。
主な用途としては、ファイルやシリアルポート等のハードウェアのクローズ処理が記述される。

また、メソッド定義の本文は暗黙的なbegin-endブロックとなっており、beginが省略されている。
メソッド定義の本文全体が例外処理の対象になり、メソッドのendで終了となる。

def sample_method
  # コード...
rescue
  # 例外処理...
end

ここでは、Rubyの基本的な構文と意味の学習に加えて、例外処理についても学習した。
Rubyには他にも非常に多くの側面がある。
次はそのような側面について理解を深めたい。

contentsへ