ちょっとこんがらがったので整理
先に結論
- 型指定なしで rescue すると、
StandardError
のサブクラスのみ catch する - アプリケーションレベルでの標準的なエラーは
RuntimeError
のサブクラス-
RuntimeError
は、StandardError
のサブクラス
-
- なので、アプリケーション内で独自の例外を書く場合、普通は
RuntimeError
を使ったほうが良い - 1.8 系の場合
Timeout::Error
は、StandardError
のサブクラスではない
raise
関数に型を渡さない時に発生する例外は、 RuntimeError
raise "エラーメッセージ" # => RuntimeError が発生
RuntimeError
って?
特定の例外クラスには該当しないエラーが起こったときに発生します。
また Kernel.#raise で例外クラスを指定しなかった場合も RuntimeError が発生します。
class RuntimeError (Ruby 2.3.0)
rescue
でクラスを省略した時にcatchする例外は、 StandardError
rescue => e # => StandardError を catch
end
通常のプログラムで発生する可能性の高い 例外クラスを束ねるためのクラスです。
StandardError とそのサブクラスは、 rescue 節でクラスを省略したときにも捕捉できます。
class StandardError (Ruby 2.3.0)
Rubyの組み込み例外は(SystemExit や Interrupt のような脱出を目的としたものを除いて) StandardError のサブクラスです。
Exception
の位置づけは?
全ての例外の祖先のクラスです。
StandardError
は、 Exception
のサブクラス
-
Exception
は、システム関係の例外も含む - アプリケーションレベルの例外であれば、
StandardError
を使うべきという思想らしい - そのため、
rescue
で、型指定をしない場合は、StandardError
を継承している例外のみcatch
する
begin
raise "エラーメッセージ" # catch する
raise Exception.new("エラーメッセージ") # catch しない
rescue => e
p e.message
end
RuntimeError
は StandardError
のサブクラス
-
StandardError
は、通常のプログラムで発生すエラーを意味するクラス- これを継承した場合は、通常のプログラムで発生すエラーを意味することになる
-
RuntimeError
は、StandardError
の中で、特定の例外クラスには該当しないエラーを意味するクラス- 「クラス指定のない
raise
」専用のクラスといえる
- 「クラス指定のない
Exception
を rescue
するとどんな時困るの?
例えばこんな時
1.upto(10) do |i|
begin
p i
sleep(1)
rescue Exception => e
p e.class
p "catch!"
end
end
これを実行中に、ctrl-c で処理を停止しようとすると、 Interrupt
例外が発生して、処理が続行されちゃう
けど、それって意図したことじゃないよね
$ ruby 01.rb
1
2
^CInterrupt
"catch!"
3
4
5
^CInterrupt
"catch!"
6
7
8
9
10
1.8 系での Timeout::Error の罠
1.8 系だとTimeout::Error が、StandardError ではなく、Interrupt を継承しているため、
型指定なしでの rescue では、catch されないという罠がある
Class: Timeout::Error (Ruby 1.8.7)
例えば、こんな時に、タイムアウトが発生しても catch されない
require 'net/http'
begin
Net::HTTP.start("test.net") do |http|
...
end
rescue =>e
...
end
例外の型指定は複数の型を指定できるので、こんな回避方法もある
begin
....
rescue Timeout::Error, StandardError =>e
end
ちなみに 1.9 系以降では、StandardError になっているので、解決している
Class: Timeout::Error (Ruby 1.9.3)