Консенсус сообщества Perl, похоже, заключается в том, что Try::Tiny
является предпочтительным способом обработки исключений.
Perl 5.14 (это версия, которую я использую) кажется, решает проблемы с помощью eval
что 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 есть исключения.
die
когда не должны, поэтому нам все еще нужно знать, какой механизм перехватит эти исключения. Будущие дизайнеры модулей, рассмотрите этот подход!
Это всегда был случай личных предпочтений. Вы предпочитаете
my $rv;
if (!eval { $rv = f(); 1 } ) {
...
}
или
my $rv = try {
f();
} catch {
...
};
Но имейте в виду, что последний использует anon subs, поэтому он беспорядок с return
, а также next
и тому подобное. Try:: Tiny try-catch вполне может оказаться намного сложнее, поскольку вы добавляете каналы связи между блоком catch и за его пределами.
Самый лучший случай (самый простой) сценарий для возврата в исключение - если $rv
всегда истинно, когда нет исключения. Он будет выглядеть следующим образом:
my $rv;
if ($rv = eval { f() }) {
...
return;
}
против
my $rv = try {
f();
} catch {
...
};
if (!$rv) {
return;
}
Вот почему я использовал TryCatch вместо Try:: Tiny, чтобы я использовал такие модуль.
Изменение на Perl просто означает, что вы можете сделать if ($@)
снова. Другими словами,
my $rv;
if (!eval { $rv = f(); 1 } ) {
...
}
можно записать
my $rv = eval { f() };
if ($@) {
...
}
Если ничего другого, Try::Tiny
по-прежнему остается синтаксическим сахаром. Если вы хотите что-то немного более тяжеловесное, там также TryCatch
, который решает некоторые проблемы, связанные с тем, что предложения в Try::Tiny
являются подпрограммами (например, что return
не оставляет закрывающей функции).
Try::Tiny
- легкий и легкий. Слишком легко. У нас было две проблемы:
return
"внутриИтак, я внес некоторые изменения в Try::Tiny
, что помогает нам. Теперь мы имеем:
try sub {},
catch 'SomeException' => sub {},
catch [qw/Exception1 Exception2/] => sub {},
catch_all sub {};
Я знаю - этот синтаксис немного экзотичен, но благодаря очевидному "sub
" наши программисты теперь знают, что оператор "return
" выходит из обработчика исключений, и мы всегда ловим только те исключения, которые хотим поймать:)
sub{}
без каких-либо изменений в Try :: Tiny: perl -MTry::Tiny -E"&try(sub { say 'A'; die qq{B\n} if $ARGV[0] }, &catch(sub { print; }));" 1
Либо выполните:
local $@;
eval { … }
..., чтобы предотвратить изменение влияния $@на глобальную область видимости или использование Try:: Tiny.
Синтаксически бывают ситуации, когда я предпочитаю один или другой.