Code Fix

中級

引数なしの rescue は StandardError の子孫しか捕まえない

クラス名を指定しない rescue は、暗黙のうちに StandardError とそのサブクラスだけを捕まえます。自作の例外クラスを Exception を直接継承させて定義すると、rescue で捕まえられずプログラムが止まります。

エラーメッセージの読み方

main.rb:4:in `<main>': custom failure (MyError)
main.rb
ファイル名
4
行番号 — 実際にクラッシュした行
<main>
発生場所 — <main> ならトップレベル、メソッド名ならそのメソッドの中
MyError
例外クラス — 何が起きたか。ここを検索するのが最短です
custom failure
詳細メッセージ — どの値が問題だったか

このエラーが出る典型パターン

パターン1

 1  class MyError < Exception    ; end
                          ^
 2  
 3  begin
 4    raise MyError, "custom failure"
 5  rescue
 6    puts "caught"
 7  end
main.rb:4:in `<main>': custom failure (MyError)

引数なしのrescueはStandardErrorの子孫しか捕まえません。Exceptionを直接継承させると素通りしてプログラムが止まります。

直し方: ExceptionStandardError にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  class ValidationError < Exception    ; end
                                  ^
 2  
 3  begin
 4    raise ValidationError, "invalid input"
 5  rescue
 6    puts "caught"
 7  end
main.rb:4:in `<main>': invalid input (ValidationError)

自作の例外クラスはStandardErrorを継承させるのが基本です。Exceptionを継承させるのはRuby自身が使う特別な場合に限られます。

直し方: ExceptionStandardError にします。

この問題を解いてみる →

パターン3

 1  class TimeoutFailure < Exception    ; end
                                 ^
 2  
 3  begin
 4    raise TimeoutFailure, "took too long"
 5  rescue
 6    puts "caught"
 7  end
main.rb:4:in `<main>': took too long (TimeoutFailure)

「rescueは何でも捕まえてくれる」という思い込みは、継承元のクラスを間違えると崩れます。

直し方: ExceptionStandardError にします。

この問題を解いてみる →

パターン4

 1  class ParseFailure < Exception    ; end
                               ^
 2  
 3  begin
 4    raise ParseFailure, "bad format"
 5  rescue
 6    puts "caught"
 7  end
main.rb:4:in `<main>': bad format (ParseFailure)

継承元をExceptionのままにすると、rescueで捕まえられずプログラムがその場で終了します。

直し方: ExceptionStandardError にします。

この問題を解いてみる →

パターン5

 1  class AuthFailure < Exception    ; end
                              ^
 2  
 3  begin
 4    raise AuthFailure, "denied"
 5  rescue
 6    puts "caught"
 7  end
main.rb:4:in `<main>': denied (AuthFailure)

自作の例外を安全にrescueで扱いたい場合は、必ずStandardErrorを継承元にしてください。

直し方: ExceptionStandardError にします。

この問題を解いてみる →

よくある誤解

「rescueは投げられた例外を種類を問わず何でも捕まえてくれるはず」という思い込みは誤りです。自作の例外クラスは StandardError を継承させないと、素の rescue の対象から外れてしまいます。

まとめ

引数なしの rescue は StandardError の子孫しか捕まえないは中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)