Rubyでの例外の発生と例外のスローの違いは何ですか?


168

Rubyには、スロー/キャッチとレイズ/レスキューという2つの異なる例外メカニズムがあります。

なぜ2つあるのですか?

どちらを使用すればよいのですか?


「ネストされたループから抜け出す」ことは、多くのプログラミング言語で共通のニーズです。@docwhatが言及gotoしたC / C ++のほかに、Javaはbreakおよびcontinueとラベルを付けました。(Pythonにもこれに対する拒否された提案があります。)
フランクリンYu

回答:


104

私はhttp://hasno.info/ruby-gotchas-and-caveatsに違いの適切な説明があると思います:

キャッチ/スローはレイズ/レスキューと同じではありません。catch / throwを使用すると、特定のシンボルに対してcatchが定義されているポイントまでブロックをすばやく終了できます。レイズレスキューは、Exceptionオブジェクトに関連する実際の例外処理です。


1
知りたくて... iPadからこれを読んでいるので、1.9ではテストできませんが、これらの落とし穴のいくつかは、最近のRubyバージョンではもう有効ではありませんよね?
Denis de Bernardy、2011年

12
また、知っておく価値raiseがあります。非常に高価です。throwではありません。ループから抜け出すためにthrowを使用gotoすると考えてください。
docwhat

4
@デニスあなたはどの落とし穴を参照していますか?
docwhat

1
リンク切れ!
モーフック2018年

パフォーマンスの違いの詳細については、ルビーのキャッチスローと効率をご覧ください。
フランクリンYu

110
  • raisefailrescue、およびensureハンドルエラーとしても知られている、例外
  • throwそして、catchされている制御フロー

他の言語とは異なり、Rubyのスローとキャッチは例外には使用されません。代わりに、追加の作業が不要になったときに実行を早期に終了する方法を提供します。(グリム、2011)

whileループのような単一レベルの制御フローの終了は、単純なで実行できますreturn。ネストされたループのように、制御フローの多くのレベルを終了するには、を使用しthrowます。

レイズとレスキューの例外メカニズムは、問題が発生したときに実行を中止するのに最適ですが、通常の処理中に深くネストされた構造からジャンプできるのは良いことです。これは、キャッチとスローが便利になる場所です。(トーマスとハント、2001)

参考文献

  1. グリム、アヴディ。「投げて、キャッチして、レイズして、レスキュー…私はとても混乱しています!」RubyLearningブログ。Np、2011年7月11日。Web。2012年1月1日。http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue--im-so-confused/
  2. トーマス、デイブ、アンドリューハント。「Rubyのプログラミング」:Pragmatic Programmer's Guide。Np、2001。Web。2015年9月29日。http://ruby-doc.com/docs/ProgrammingRuby/html/tut_exceptions.html

2
Avdiはポッドキャストで聞こえるように見えませ
hrdwdmrbl 2013年

2
Ruby Learningリンクが機能していないようです。違いを説明する別のブログ投稿があります:danielchangnyc.github.io/blog/2013/10/23/throw-raise
Dennis

おかしい、rubylearning.comはAvdiの記事がまだ残っていると考えてます。だから、SOにデータをコピーするので、失われることはありません。
Jared Beck

21

https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raiseは、改善できるとは思えない優れた説明を提供します。要約すると、私が行くにつれてブログの投稿からいくつかのコードサンプルにニックを入れます:

  1. raise/ rescueは、他の言語(またはPythonの/ )でおなじみのthrow/ catch構造に最も近いものです。エラー状態が発生し、それを別の言語で上書きする場合は、Rubyを使用する必要があります。raiseexceptthrowraise

  2. Rubyのthrow/をcatch使用すると、実行を中断し、catchraise/のようにrescue)スタックを探して上昇できますが、実際にはエラー状態を意図していません。これはめったに使用されるべきではなく、「対応するスタックが見つかるまでスタックをウォークするcatch」動作が、作成しているアルゴリズムにとって理にかなっている場合にのみ存在しますがthrow、をエラーに対応すると考えるのは意味がありません。状態。

    Rubyで使用されるキャッチアンドスローとは何ですか?throw/ catchコンストラクトの素敵な使い方に関するいくつかの提案を提供します。

それらの間の具体的な行動の違いは次のとおりです。

  • rescue FooFooサブクラスを含むインスタンスを救出しますFoo同じオブジェクトcatch(foo)のみをキャッチしますFoocatchクラス名を渡してインスタンスをキャッチできないだけでなく、等価比較も行いません。例えば

    catch("foo") do
      throw "foo"
    end

    ご提供しますUncaughtThrowError: uncaught throw "foo"(またはArgumentError2.2より前にルビーのバージョンでは)

  • 複数のレスキュー条項をリストすることができます...

    begin
      do_something_error_prone
    rescue AParticularKindOfError
      # Insert heroism here.
    rescue
      write_to_error_log
      raise
    end

    複数のcatchesをネストする必要がありますが...

    catch :foo do
      catch :bar do
        do_something_that_can_throw_foo_or_bar
      end
    end
  • bare rescuerescue StandardError、慣用的な構成要素と同等であり、慣用的な構成要素です。のcatchような「ベア」はcatch() {throw :foo}何もキャッチせず、使用すべきではありません。


良い説明ですが、疑問を投げかけます。なぜ彼らは、いったいなぜ彼らはルビーでレイズをデザインするのですか?そして、スローも含みますが、他の言語では!=スローです。元のロジックが表示されない
ワイヤード00 '09 / 09/18

@ wired00 (シュラグ)今日の他の人気のある言語に比べてかなり風変わりだと思う。
Mark Amery

2
@ wired00:1960年代に構造化エラー処理の最初の実験が行われて以来、例外の「発生」と呼ばれてきました。これは、最新の例外処理を発明した独創的な記事で「発生」の例外と呼ばれ、 Rubyの主なインスピレーションの一部であるLispsとSmalltalksでの例外の「発生」。これは、「プログラミングの概念の前でさえ存在していたハードウェアでの例外の発生」または「割り込みの発生」と呼ばれます。言語」が存在しました。問題はむしろ、他の言語がなぜそれを変更したのかということです。
イェルクWミッターク

@MarkAmery:これらの「他の一般的な言語」の多くがあることを覚えておいてください若いルビーよりまたは少なくとも現代。だから、問題はむしろそうでなければならない:なぜ他の言語がRuby(そしてSmalltalkとLispとハードウェアと文献)に従わなかったのか。
イェルクWミッターク

@JörgWMittag興味深い-あなたは私に小さな歴史的研究をするように促しました。C ++は、Rubyが登場する数年前に例外を「投げる」という考えを持っていました。english.stackexchange.com / a / 449209/73974によれば、この用語は実際には70年代にさかのぼります。確立された用語を取り、それを使用して完全に異なる何かを意味する。
Mark Amery
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.