Rubyの例外
例外と実行は常にリンクされています。存在しないファイルを開いて状況を適切に処理しなかった場合、プログラムの品質は低いと見なされます。
例外が発生するとプログラムは停止します。例外は、プログラムの実行中に発生する可能性のあるさまざまなタイプのエラーを処理するために使用されるため、プログラムを完全に停止させることなく適切なアクションが実行されます。
Ruby は、例外を処理するための完璧なメカニズムを提供します。例外をスローする可能性のあるコードを begin/end ブロックで囲み、rescue 節を使用して Ruby にどのタイプの例外を処理するかを指示できます。
文法
begin #开始 raise.. #抛出异常 rescue [ExceptionType = StandardException] #捕获指定类型的异常 缺省值是StandardException $! #表示异常信息 $@ #表示异常出现的代码位置 else #其余异常 .. ensure #不管有没有异常,进入该代码块 end #结束
beginからrescueまですべてが保護されています。コード ブロックの実行中に例外が発生した場合、制御は rescue と end の間のブロックに渡されます。
beginブロック内のrescue句ごとに、Rubyはスローされた例外を各引数と順番に比較します。レスキュー句で指定された例外が、現在スローされている例外と同じ型であるか、その例外の親クラスである場合、一致は成功します。
例外が指定されたすべてのエラー タイプに一致しない場合は、すべての rescue 句の後に else 句を使用できます。
例
#!/usr/bin/ruby begin file = open("/unexistant_file") if file puts "File opened successfully" end rescue file = STDIN end print file, "==", STDIN, "\n"
上記の例の出力結果は以下の通りです。 openが失敗したため、STDINがfileを置き換えていることがわかります。
#<IO:0xb7d16f84>==#<IO:0xb7d16f84>
retryステートメントの使用
rescueブロックを使用して例外をキャッチし、次にretryステートメントを使用してbeginブロックの先頭から実行を開始できます。
構文
begin # 这段代码抛出的异常将被下面的 rescue 子句捕获 rescue # 这个块将捕获所有类型的异常 retry # 这将把控制移到 begin 的开头 end
例
#!/usr/bin/ruby begin file = open("/unexistant_file") if file puts "File opened successfully" end rescue fname = "existant_file" retry end
以下が処理の流れです:
オープン中に例外が発生しました。
救助にスキップしてください。 fname が再割り当てされます。
再試行により、begin の先頭にジャンプします。
今度はファイルが正常に開きました。
基本的なプロセスを続けます。
注: 名前を変更したファイルが存在しない場合、この強制コードは無限に試行されます。したがって、例外を処理するときは、注意して retry を使用してください。
raise ステートメントを使用する
raise ステートメントを使用して例外をスローできます。次のメソッドは呼び出されると例外をスローします。 2 番目のメッセージが出力されます。
構文
raise 或 raise "Error Message" 或 raise ExceptionType, "Error Message" 或 raise ExceptionType, "Error Message" condition
最初の形式は、現在の例外 (または、現在の例外がない場合は RuntimeError) を単純に再スローします。これは、例外を渡す前に解釈する必要がある例外ハンドラーで使用されます。
2 番目の形式は、新しい RuntimeError 例外を作成し、そのメッセージを指定された文字列に設定します。その後、例外が呼び出しスタックにスローされます。
3 番目の形式は、最初のパラメーターを使用して例外を作成し、関連するメッセージを 2 番目のパラメーターとして設定します。
4 番目の形式は 3 番目の形式に似ており、追加の条件ステートメント (unless など) を追加して例外をスローできます。
例
#!/usr/bin/ruby begin puts 'I am before the raise.' raise 'An error has occurred.' puts 'I am after the raise.' rescue puts 'I am rescued.' end puts 'I am after the begin block.'
上記の例の出力結果は次のとおりです:
I am before the raise. I am rescued. I am after the begin block.
raiseの使用法を示す別の例:
#!/usr/bin/ruby begin raise 'A test exception.' rescue Exception => e puts e.message puts e.backtrace.inspect end
上記の例の出力結果は次のとおりです:
A test exception. ["main.rb:4"]
ensureステートメントを使用します
場合によっては、例外がスローされるかどうかに関係なく、コード ブロックの最後で何らかの処理が完了していることを確認する必要があります。たとえば、ブロックに入るときにファイルが開いている場合、ブロックから出るときは必ずファイルを閉じる必要があります。
これがensure 句の動作です。 ensure は最後のレスキュー句の後に配置され、ブロックの終了時に常に実行されるコード ブロックが含まれます。ブロックが正常に終了するか、例外がスローされて処理されるか、キャッチされない例外で終了するかに関係なく、ensure ブロックは常に実行されます。
文法
begin #.. 过程 #.. 抛出异常 rescue #.. 处理错误 ensure #.. 最后确保执行 #.. 这总是会执行 end
例
begin raise 'A test exception.' rescue Exception => e puts e.message puts e.backtrace.inspect ensure puts "Ensuring execution" end
上記の例の出力結果は次のとおりです:
A test exception. ["main.rb:4"] Ensuring execution
elseステートメントを使用します
else句が提供される場合、通常はrescue句の後に配置されます。事前に必ず確認してください。
else 句の本体は、コードの本体が例外をスローしない場合にのみ実行されます。
構文begin
#.. 过程
#.. 抛出异常
rescue
#.. 处理错误
else
#.. 如果没有异常则执行
ensure
#.. 最后确保执行
#.. 这总是会执行
end
例begin
# 抛出 'A test exception.'
puts "I'm not raising exception"
rescue Exception => e
puts e.message
puts e.backtrace.inspect
else
puts "Congratulations-- no errors!"
ensure
puts "Ensuring execution"
end
上記の例の出力結果は次のとおりです: I'm not raising exception Congratulations-- no errors! Ensuring execution$! 変数を使用して、スローされたエラー メッセージをキャプチャします。 Catch と Throwraise と Rescue の例外メカニズムは、エラーが発生したときに、通常の処理中に深くネストされた構造からジャンプする必要がある場合があります。ここでキャッチアンドスローが役に立ちます。
catch は、指定された名前 (シンボルまたは文字列) をラベルとして使用するブロックを定義します。ブロックはスローが発生するまで通常どおり実行されます。
構文throw :lablename
#.. 这不会被执行
catch :lablename do
#.. 在遇到一个 throw 后匹配将被执行的 catch
end
或
throw :lablename condition
#.. 这不会被执行
catch :lablename do
#.. 在遇到一个 throw 后匹配将被执行的 catch
end
例 次の例では、ユーザーがプロンプトに応じて「!」と入力すると、ユーザーとの対話を終了するためにスローが使用されます。 def promptAndGet(prompt) print prompt res = readline.chomp throw :quitRequested if res == "!" return res end catch :quitRequested do name = promptAndGet("Name: ") age = promptAndGet("Age: ") sex = promptAndGet("Sex: ") # .. # 处理信息 end promptAndGet("Name:")上記のプログラムは人間の介入を必要としますが、コンピュータ上で試すことができます。上記の例の出力結果は次のようになります:
Name: Ruby on Rails Age: 3 Sex: ! Name:Just RubyClass ExceptionRuby の標準クラスとモジュールは例外をスローします。最上位の Exception クラスを含め、すべての例外クラスは階層を形成します。次のレベルは 7 つの異なるタイプです:
- Interrupt
- NoMemoryError
- SignalException
- ScriptError
- StandardError
- SystemExit
class FileSaveError < StandardError attr_reader :reason def initialize(reason) @reason = reason end end次に、上記の例外が使用される次の例を見てください:
File.open(path, "w") do |file| begin # 写出数据 ... rescue # 发生错误 raise FileSaveError.new($!) end endここで、最も重要な行は raise
FileSaveError.new($!) です。 raise を呼び出して例外が発生したことを示し、特定の例外によりデータの書き込みに失敗した FileSaveError の新しいインスタンスに例外を渡します。