プログラムの動作に例外的な状況はつきものだ.ファイルをオープ ンしようとすれば,ファイルが存在しないかも知れないし,書き込 もうとすれば,ディスクがいっぱいかも知れない.こういう状況を 考慮していないプログラムは品質が悪いといわれる.
問題は例外的な状況が発生したかどうかが,いちいち「今の処理は 大丈夫でしたか」と確認しなければ分からないことだ.例外的な状 況で処理が正しく行われていないのに続きを実行すれば,当然問題 が起きる.例外的な状況が発生したら,そのまま処理を続けてはい けないのだ.
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に代わりのファイル名を代入し てやり直すわけだ.処理の流れは以下のようになる.
しかし,例えば再代入した名前のファイルも存在しなければ,この 例では無限ループに陥ってしまう.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