CATCHブロックでの例外と失敗の区別[RAKU]


9

失敗はCATCHブロックで処理できることがわかっています。

次の例では、「AdHoc」障害(other-sub内)を作成し、CATCHブロック(my-sub内)で例外を処理します。

sub my-sub {
    try {
        CATCH {
            when X::AdHoc { say 'AdHoc Exception handled here'; .resume }
            default {say 'Other Exception'; .resume}
        }

        my $b = other-sub();

        $b.so ?? $b.say !! 'This was a Failure'.say;
    }
}

sub other-sub { fail 'Failure_X' }

my-sub();

出力は次のとおりです。

AdHoc Exception handled here
This was a Failure

しかし、私の質問は次のとおりです。2つのケースを区別するために、CATCHブロックで障害と「通常の」例外をどのように区別できますか?

回答:


12

間の関係Failureとは、ExceptionということであるFailure持っているException-と言うことですつまり、それは、その状態の一部として例外オブジェクトを保持しています。このようなもの:

class Failure {
    has Exception $.exception;
    # ...
}

Failure「爆発」すると、Exceptionその中にあるをスローすることで爆発します。したがって、CATCHブロックに到達するのはExceptionオブジェクトであり、囲んでFailureいるへのリンクはありません。(実際、与えられたExceptionオブジェクトは原則として多くFailureのによって保持されます。)

したがって、これを検出する直接的な方法はありません。設計の観点からは、おそらくそうすべきではなく、問題を解決する別の方法を見つける必要があります。A Failureは、例外のスローを延期し、それを値として処理できるようにするための単なる方法です。制御フローの即時転送ではなく値として伝達されるため、根本的な問題の性質が変化することは意図されていません。残念ながら、元の目標は質問に記載されていませんでした。コントロールの例外を確認すると便利ですが、それ以外の場合は、解決しようとしている根本的な問題について別の質問を投稿することもできます。おそらくもっと良い方法があります。

完全を期すために、私はそこにいることに注意しましょうしている 1があることを検出することができることを、間接的な方法ExceptionによってスローされましたがFailure。たとえば.backtrace、例外オブジェクトのを取得して上部フレームのパッケージを見ると、それがからのものであると判断できますFailure

sub foo() { fail X::AdHoc.new(message => "foo") }
try {
    foo();
    CATCH {
        note do { no fatal; .backtrace[0].code.package ~~ Failure };
        .resume
    }
}

ただし、これは簡単に変更できる実装の詳細に大きく依存しているため、私はそれに依存しません。


明確にするために、私の意図は例外(CATCHブロック内)のみを処理することです。失敗した場合は、何も起こらなかったかのように再開し、残りのコード(CATCHの外)で失敗を処理します。私の例では、返されたエラーが含まれている例外をトリガーすることを期待していませんでした!私がしたことは、$ bで結果を取得し、それをブール値としてチェックすることだけです。それは、私の見解では、失敗の「使用」を構成するものではなく、したがってCATCHブロックのトリガーを構成するものではありません。その代わりに、CATCHは常に失敗に含まれる例外を処理しているようです!!
ジャカル

さらに、例では、失敗を検出する間接的な方法について、返されたBool(失敗タイプのスマートチェックから)の値は「False」です。しかし、私はそれが「真」であると予想しました!私は何か見落としてますか???
ジャカル

1
@jakar tryブロックはuse fatalプラグマを意味します。つまりFailure、ブロックで行われた呼び出しから返されたものはすべて、すぐに例外に変換されます。使用しないでくださいtry。a CATCHはRakuのどのブロックにも入ることができます(したがって、それをのレベルに置くだけsubです)。または、ブロックno fatalの上部に書き込みますtry
ジョナサンワージントン

そして、私の2番目のコメントはどうですか?
ジャカル

1
True私がローカルに持っているRakudoバージョンでプリントを与えた例を実行します。それがあなたのものでない場合、それはこれを行うことの脆弱性についての要点を証明するだけです。
ジョナサンワージントン

6

tryラッパーを削除するだけです。

sub my-sub {

#    try {              <--- remove this line...

        CATCH {
            when X::AdHoc { say 'AdHoc Exception handled here'; .resume }
            default {say 'Other Exception'; .resume}
        }

        my $b = other-sub();

        $b.so ?? $b.say !! 'This was a Failure'.say;

#    }                  <--- ...and this one

}

sub other-sub { fail 'Failure_X' }

my-sub();

使用しましたtry。A tryはいくつかのことを行いますが、ここでの適切なことはFailure、その範囲内のすべてのをすぐに例外に昇格するようにRakuに指示することです。これは、あなたが望まないことです。したがって、最も簡単な解決策は、それをやめることです。


この回答は、jnthnの説明の一部を冗長に繰り返すだけです(彼が回答の下に書いた特にコメントを参照してください)。しかし、私はすべての読者がこの側面を見つけて理解するだろうとは確信していなかったし、jnthnの回答についてのコメントも2つも役立つとは思わなかったため、この回答が役に立ちました。

私はこれをコミュニティの回答として書きました。これは明らかにそれを保証するものではないため、賛成投票の恩恵を受けないようにするためです。十分な反対票が出た場合は、削除します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.