Rubyの例外とその捕捉――基本のbegin〜rescue〜endからensure、else、retry、後置rescueまで:若手エンジニア/初心者のためのRuby 2.1入門(9)(3/4 ページ)
オープンソースのオブジェクト指向プログラミング言語「Ruby」の文法を一から学ぶための入門連載。最新版の2.1に対応しています。今回は、例外とその補足について、begin、rescue、end、ensure、else、retry、後置rescueなどの基本的な使い方を交えて解説します。
例外を「捕捉」して処理する
ここまで、例外の仕組みの概要と、例外を発生させる方法について紹介しました。ここでは、例外を捕捉して処理する方法について解説します。
基本形「begin〜rescue〜end」
例外を捕捉するための基本形を、exception02.rbに示します。
begin raise "something wrong" rescue => e puts "An exception is occurd!" p e p $! end
$ ruby exception02.rb An exception is occurd! #<RuntimeError: something wrong> #<RuntimeError: something wrong>
例外を捕捉したいコードを「begin〜rescue」の間に記述し、例外が起きた場合の処理を「rescue〜end」の間に記述します。また、「rescue => e」のように記述することで、rescue〜end間で変数eに例外オブジェクトが格納されます。また、グローバル変数「$!」を参照することで例外オブジェクトを扱うこともできます。
ここでは、2行目でraiseメソッドを使ってRuntimeErrorを発生させているので、実行結果の3行目でRuntimeErrorと、raiseメソッドに設定したメッセージ「something wrong」が出力されていることが分かります。
例外クラスを指定して捕捉する
基本形で紹介した方法では、例外クラスの種類に応じて処理を振り分けたい場合、rescue〜end間でif文などを使って、例外オブジェクトのクラスを参照して処理を分岐させる必要があります。実は、そのようなことをしなくても、exception03.rbのように記述すれば、例外オブジェクトのクラスに応じて処理を振り分けられます。
require_relative "exception01" begin teapot = Teapot.new("coffee") puts teapot.pour_out rescue UnacceptableRequidError => e puts "Rescued in 'UnacceptableRequiedError => e'" p e p e.obj rescue NoMethodError, ZeroDivisionError => e puts "Rescued in 'rescue NoMethodError, ZeroDivisionError => e'" p e end
$ ruby exception03.rb Rescued in 'UnacceptableRequiedError => e' #<UnacceptableRequidError: unacceptable> "coffee"
require_relativeでexception01.rbのコードを利用するので、exception03.rbはexception01.rbと同じディレクトリに配置してください。
例外クラスに応じて処理を振り分ける場合は、6行目や9行目のように、rescueに続けて例外クラスを指定します。また、10行目のように複数の例外クラスを指定することもできます。
ここでは、コードの4行目で、Teapotが許容しない「coffee」でTeapotオブジェクトを生成しようとしています。UnacceptableRequidError自体はTeapotの基底クラス、Vesselのpour_inメソッドの中で発生します。しかし、pour_inメソッドの中では例外を捕捉しないため、コールスタック(呼ばれたメソッドを順々に積んだスタック)をさかのぼっていき、最終的にexception03.rbに記述されているbegin〜end節で捕捉されます。
この例では「Teapot.new("coffee")」で例外が発生するため、5行目は実行されず7行目に処理が移ります。Rubyのインタプリタは複数記述されたrescueを上から順番にチェックし、初めて合致した例外クラスの例外処理に分岐させるため、11〜12行目の処理は実行されません。
また、exception01.rbではUnacceptableRequidErrorで@objというインスタンス変数を設定したことを思い出してください。そのため、コードの9行目と実行結果の4行目のように、どのようなオブジェクトを設定しようとして例外が発生したのかを知ることができます。
もし、rescueに設定されたどの例外クラスにも合致しない場合、exception04.rbのように、例外の捕捉が行われないのでプログラムはその場で停止し、エラーメッセージが出力されます。
require_relative "exception01" begin bottle = Bottle.new("water") bottle.pour_out rescue UnacceptableRequidError => e puts "Rescued in 'UnacceptableRequiedError => e'" p e rescue NoMethodError, ZeroDivisionError => e puts "Rescued in 'rescue NoMethodError, ZeroDivisionError => e'" p e end
$ ruby exception04.rb exception04.rb:4:in `<main>': uninitialized constant Bottle (NameError)
ここでは4行目で、定義されていないBottleクラスを使おうとしています。Bottleクラスは定義されていないので、NameErrorという例外が発生して処理が止まってしまいます。シチュエーションによっては、これでは困ることもあるでしょう。そのような場合、exception05.rbのように、StandardErrorを指定して捕捉するとよいでしょう。
require_relative "exception01" begin bottle = Bottle.new("water") bottle.pour_out rescue UnacceptableRequidError => e puts "Rescued in 'UnacceptableRequiedError => e'" p e rescue NoMethodError, ZeroDivisionError => e puts "Rescued in 'rescue NoMethodError, ZeroDivisionError => e'" p e rescue StandardError => e # rescue => e でもOK puts "Rescued in 'rescue StandardError => e'" p e end
$ ruby exception05.rb Rescued in 'rescue StandardError => e' #<NameError: uninitialized constant Bottle>
exception04.rbの記述に加え、12〜14行目にStandardErrorを捕捉するrescueを記述しています。例外クラスの合致判定を行うとき、発生した例外クラスの基底クラスも対象とします。NameErrorはStandardErrorから派生しているため、無事12行目で捕捉できます。
また、コード中のコメントに書いている通り、StandardErrorを捕捉する場合は、「rescue => e」というように省略して書くことができます。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
公用語に英語、「再起動」したRubyKaigi 2013が東京で開催
いったん終了していたRubyコミュニティ主催の年次イベントが再開。技術色、国際色を強め、盛況のうちに幕を閉じたWeb業界、今から行くならRubyエンジニアが狙い目?
不況で冷え込んでいたIT業界の転職市場に、回復の兆しが見え始めている。だが、業種や職種によって採用数や条件に大きな差異が生まれている。転職市場の動向を追い、自身のキャリア戦略立案に生かしてほしい。Ruby 2.0.0がリリース、大規模化対応の機能などを搭載
生誕20年となる節目を迎えて、プログラミング言語「Ruby」の最新版がリリースされた- 新バージョンで何が変わるのか、Rubyはどこへ向かうのか:まつもと×笹田、Ruby 1.9を語る
- いよいよ始まるRuby 1.9への移行:開発コアメンバが語るRubyの今とこれから(前編)
- Rubyの今後の進化の方向性とは?:開発コアメンバが語るRubyの今とこれから(後編)
- 互換性や脆弱性の問題にどう対応していくのか:Rubyが抱える課題、NaClの前田氏が講演
- Rails Hub情報局:「なんでRubyなんか作った!? 迷惑だ!」に対するMatzの答え
- Rails Hub情報局:Rubyはイノベーション言語として選ばれている
- Rails Hub情報局:Rubyのまつもと氏は、一発屋で終わるのか?
- Rails Hub情報局:Rubyに魔法は要らない
- 数々の“スペル”で高度なプログラミング:Rubyの魔術
- 晴読雨読@エンジニアライフ:『たのしい開発 スタートアップRuby』――なぜRubyistたちはあれほど楽しそうなのか
「JRuby 1.7.0」登場、1年半ぶりのメジャーアップデート
JavaVM上のRuby実装「JRuby」の最新版となる「JRuby 1.7.0」が、10月22日にリリースされた。