Perlコミュニティのコンセンサスはそのようです Try::Tiny
は、例外を処理するための推奨される方法です。
Perl 5.14(私が使用しているバージョン) 解決するようですissues with eval
that Try::Tiny
アドレス。ウィルTry::Tiny
まだメリットがありますか?
私の回答は不評ですが、PerlプログラマーがPerlで「例外」と呼ぶものの非常に貧弱な概念を使用しようとするべきではないと私は思います。これらは基本的にサイドチャネルの戻り値です。ただし、例外のアイデアに夢中のままであり、グローバル変数を使用して状態を渡すのが複雑であっても、人々はそれを機能させようと試み続けています。
しかし実際には、人々はdie
を使用して失敗を知らせます。参照でdie
を実行してエラーオブジェクトを返すことができると言う人もいますが、そのためにdie
は必要ありません。オブジェクトがあるので、オブジェクトのすべての力を使用する必要があります。
sub some_sub {
...
return Result->new( error => 1, description => ... ) if $something_went_wrong;
return Result->new( error => 0, ... );
}
my $result = some_sub( ... );
if( $result->is_error ) { ... };
これには、グローバル変数、遠くでの行動、スコーピングの頭痛、特別な特別措置は必要ありません。小さなクラスResult
またはそれを呼び出したいものを作成して戻り値をラップし、アイデンティティのない単一の値ではなく構造化されたデータを取得します。戻り値が何を意味するのか疑問に思うことはもうありません。それはundef
が実際の値ですか、それとも障害の兆候ですか?戻り値が定義されている場合、またはそれが真である場合、それは良いですか?オブジェクトはこれらのことを教えてくれます。また、die
で同じオブジェクトを使用できます。 die
ですでにオブジェクトを使用していて、それを戻り値として使用している場合、$@
を許容するために必要なすべての追加のことを推奨することはほとんどありません。
これについては、 "例外をスローする代わりにエラーオブジェクトを返す" で詳しく説明します。
ただし、他の人がやっていることを手伝うことはできないので、Perlに例外があると見せかける必要があります。
それは常に個人的な好みのケースでした。あなたのお好みは
_my $rv;
if (!eval { $rv = f(); 1 } ) {
...
}
_
または
_my $rv = try {
f();
} catch {
...
};
_
ただし、後者はanon subsを使用するため、return
だけでなく、next
なども使用することに注意してください。 Try :: Tinyのtry-catchは、catchブロックとその外側の間に通信チャネルを追加すると、はるかに複雑になる可能性があります。
例外で戻るための最良のケース(最も簡単な)シナリオは、例外がないときに_$rv
_が常にtrueである場合です。次のようになります。
_my $rv;
if ($rv = eval { f() }) {
...
return;
}
_
対
_my $rv = try {
f();
} catch {
...
};
if (!$rv) {
return;
}
_
そのため、私は Try :: Tiny の代わりに TryCatch を使用しましたが、そのようなモジュールを使用しました。
Perlへの変更は、単にif ($@)
を再度実行できることを意味します。言い換えると、
_my $rv;
if (!eval { $rv = f(); 1 } ) {
...
}
_
書くことができます
_my $rv = eval { f() };
if ($@) {
...
}
_
他に何もない場合でも、Try::Tiny
は依然として素晴らしい構文糖衣です。もう少し重いものが必要な場合は、 TryCatch
も使用できます。これにより、Try::Tiny
の句がサブルーチンであるという事実に関連するいくつかの問題が解決されます(たとえば、return
は囲み関数を残しません)。
Try::Tiny
は簡単で軽量です。簡単すぎる。 2つの問題がありました。
return
'ステートメントには常に問題がありましたそこで、Try::Tiny
にいくつかの変更を加えました。今私たちは持っています:
try sub {},
catch 'SomeException' => sub {},
catch [qw/Exception1 Exception2/] => sub {},
catch_all sub {};
私は知っています-この構文は少し変わっていますが、明白な 'sub
'のおかげで、プログラマーは 'return
'ステートメントが例外ハンドラーからのみ終了し、常にこの例外のみをキャッチすることを知っていますキャッチしたいもの:)
次のいずれかを実行します。
local $@;
eval { … }
…$ @への変更がグローバルスコープに影響しないようにするか、Try :: Tinyを使用します。
構文的には、どちらか一方を好む状況があります。