例外

Rubyではプログラム上で異常が発生した時に「例外」が発生し、そこで実行が停止します。これにより、プログラムの構造をシンプルにすることができます。

また、ユーザプログラムで例外を発生させたり、例外を捕捉して回復のための処理を記述することも可能です。


例外を捕捉する

begin-rescue-ensure-end構文で例外を捕捉し、その回復処理を記述することができます。

■構文
begin
  式..
[rescue [error_type,..] [=> evar] [then]
  式..]..
[else
  式..]
[ensure
  式..]
end

begin
  # 実行する処理
rescue
  # 例外が発生したときの処理
else
  # 例外が発生しなかったときに実行される処理
ensure
  # 例外の発生有無に関わらず最後に必ず実行する処理
end

■例
begin
  dest = open("backup/passwd", "w")
  source = open("/etc/passwd")
rescue
  Dir::mkdir("backup")
  retry
else
  dest.write(source.read)
  dest.close
  source.close
ensure
  puts "script end."
end

特定の例外だけを捕捉する

rescueの後に捕捉する例外を明示することで、特定の例外だけを捕捉することができます。

begin
  # 略
rescue Errno::EEXIST
  # Errno::EEXIST(mkdirで既にディレクトリが存在する場合)を捕捉した場合の処理
end

種類が指定されない場合、"StandardError?"が省略されたと認識されるようです。

例外処理の後に処理をやり直す

rescue節の中でretry文を使うと、例外処理の後に処理をやり直すことができます。

■例
begin
  dest = open("backup/passwd", "w")
  source = open("/etc/passwd")
rescue
  Dir::mkdir("backup")
  retry
else
  dest.write(source.read)
  dest.close
  source.close
ensure
  puts "script end."
end

例外の内容を受け取る

rescueの後に"=> (変数)"とすることで上がってきた例外を捕捉できます。つまり、上がってきた例外が指定した変数に代入されます。

begin
  raise "error!"
rescue => exc
  p exc
end

種類の指定と組み合わせることもできます。

begin
  # ...
rescue Errno::EEXIST => e
  print "error raised: "
  p e
  # ...
end

例外を発生させる

raiseを使用すると意図的に例外を発生させることができます。

種類を指定しなければ、RuntimeError?クラスの例外になります。

raise #=> RuntimeError:
raise "format error" #=> RuntimeError: format error

種類を指定する場合、ふたつ方法があります。

カンマで区切って例外クラスとメッセージを書く

raise NotImplementedError #=> NotImplementedError: NotImplementedError
raise ArgumentError, "invalid argument" #=> ArgumentError: invalid argument

例外オブジェクトを生成して指定する

raise IndexError.new("index out of range") #=> IndexError: index out of range

いずれの場合も、例外のクラスはExceptionクラスの下位クラスでなければなりません。

独自の例外を定義し発生させる

Exceptionクラスのサブクラスを定義するとユーザ独自の例外クラスを定義することができます。

class SampleException < Exception; end
raise SampleException, "format error." #=> format error. (SampleException)

自作の例外を捕まえる時には、名前を明示しなければなりません。

begin
  raise SampleException
rescue SampleException
  p "format error"
end

種類を指定しないrescueで捕まえられるようにするには、StandardError?を使って定義します。

class SampleException < StandardError; end
begin
  raise SampleException
rescue
  # ...
end

省略記法(def)

メソッド定義全体にかかる場合はbeginとendを省略できるようです。

def some_method
  begin
    # ...
  rescue
    # ...
  end
end
def some_method
  # ...
rescue
  # ...
end

else, =>, ensureなどその他の文法も問題なく使えます。

省略記法(後置)

ifなどと同様、rescueでも後置記法ができます。

begin
  # (1)
rescue
  # (2)
end

に対応して

(1) rescue (2)

とします。 種類を指定して受けることはできませんが、特殊変数 $! によって捕まった例外を表すオブジェクトを参照できます。



Comments