Google

- コピー - - 目次

例外処理


プログラムの動作に例外的な状況はつきものだ.ファイルをオープ ンしようとすれば,ファイルが存在しないかも知れないし,書き込 もうとすれば,ディスクがいっぱいかも知れない.こういう状況を 考慮していないプログラムは品質が悪いといわれる.

問題は例外的な状況が発生したかどうかが,いちいち「今の処理は 大丈夫でしたか」と確認しなければ分からないことだ.例外的な状 況で処理が正しく行われていないのに続きを実行すれば,当然問題 が起きる.例外的な状況が発生したら,そのまま処理を続けてはい けないのだ.

rubyではこういう例外的な状況では「例外」が発生する.特になに も対処しなければ,「例外」はプログラムの実行を中断する.これ で例外的な状況に対処せずに処理を続けてしまう心配は無い.


 ruby> file =open("/file_not_exist")
 ERR: No such file or directory - /file_not_exist

Cなどならオープンできたかプログラマがチェックする必要がある が.rubyでは「例外が発生していないのでちゃんと処理が行われた」 と仮定することができる.Cで書くとこういう風になる.


FILE *file = fopen("/file_not_exist", "r");
if (file == NULL) { /* エラー処理 */ }

エラー処理する必要がない分,プログラムがすっきりするのが分か るだろう.

先程も説明したように,例外が発生すると,プログラムの実行は中 断される.が,それでは嬉しくないことも多いだろう.例外の原因 に対応してプログラムを継続したい場合もあるはずだ.そういう時 には'begin'を使って,例外を捕捉する必要がある.使い方はこう だ.


 ruby> begin
 ruby|   file = open("/file_not_exists")
 ruby| rescue
 ruby|   file = STDIN
 ruby| end
 #<IO:0x93490>
 ruby> print file, "==", STDIN, "\n"
 #<IO:0x93490> == #<IO:0x93490>
 nil

openに失敗したので,fileにSTDINが代入されたのが分かるだろう.

beginは本体を実行している最中に例外が起きるとrescue以下のエ ラー処理を実行する.

beginには「やり直し」の機能もある.これには`retry'を使う. rescueの中でretryが使われるとbeginのはじめから実行をやり直す. これを応用するとこんな感じになる.


 ruby> fname = "file_not_exists"
 ruby> begin
 ruby|   file = open(fname)
 ruby|   # なにか file を使った処理
 ruby| rescue
 ruby|   fname = "file_exists"
 ruby|   retry
 ruby| end
 #<File:0x68890>

fileのオープンに失敗するとfnameに代わりのファイル名を代入し てやり直すわけだ.処理の流れは以下のようになる.

  • openで例外が発生する
  • rescue以下へ,fnameに再代入する
  • retryでbeginの最初に
  • 今度はopenで成功する
  • 本来の処理

しかし,例えば再代入した名前のファイルも存在しなければ,この 例では無限ループに陥ってしまう.retryを使う時には,例外処理 に気を使った方が良い.

rubyのライブラリはエラーが起きた時に例外を発生させるようになっ ているが,もちろん自分で例外を発生させることができる.例外を 発生させるには`raise'を使う.raiseには例外の状況を説明する文 字列を引数に与える.この文字列は説明する必要がない時には省略 できる(が省略しない方が良い).この文字列は後から変数`$!'で参 照できる.


 ruby> raise "test error"
 ERR: test error
 ruby> begin
 ruby|   raise "test2"
 ruby| rescue
 ruby|   print $!, "\n"
 ruby| end
 test2
 nil

- コピー - - 目次