Try :: Tiny все еще рекомендуется для обработки исключений в Perl 5.14 или новее?

70

Консенсус сообщества Perl, похоже, заключается в том, что Try::Tiny является предпочтительным способом обработки исключений.

Perl 5.14 (это версия, которую я использую) кажется, решает проблемы с помощью eval что Try::Tiny адреса. Будет ли Try::Tiny предоставлять какие-либо льготы для меня?

  • 6
    Мне также интересен ответ сообщества на это! Хороший вопрос!
Теги:
exception-handling

5 ответов

32
Лучший ответ

Мой ответ непопулярен, но я не думаю, что программисты на 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 есть исключения.

  • 2
    Я согласен, но, как вы сказали в конце, есть модули, которые die когда не должны, поэтому нам все еще нужно знать, какой механизм перехватит эти исключения. Будущие дизайнеры модулей, рассмотрите этот подход!
  • 6
    Очень хорошее решение, но у die / exception есть одно большое преимущество: распространение через стек дополнительных вызовов. Я имею в виду: не проверяйте на прохождение или провал какого-либо вызова подпрограммы - просто не поймайте исключение. Это будет распространяться до тех пор, пока кто-то не поймает это.
Показать ещё 7 комментариев
28

Это всегда был случай личных предпочтений. Вы предпочитаете

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 ($@) {
   ...
}
  • 4
    Если вам не нужно перехватывать значение, возвращаемое eval (что, по крайней мере, для меня является наиболее распространенным случаем) - тогда eval-версия становится немного проще.
  • 0
    TryCatch имеет гораздо меньше предупреждений, чем Try :: Tiny, и это намного быстрее. Есть одна оговорка, она отвратительно медленно загружается.
Показать ещё 5 комментариев
13

Если ничего другого, Try::Tiny по-прежнему остается синтаксическим сахаром. Если вы хотите что-то немного более тяжеловесное, там также TryCatch, который решает некоторые проблемы, связанные с тем, что предложения в Try::Tiny являются подпрограммами (например, что return не оставляет закрывающей функции).

10

Try::Tiny - легкий и легкий. Слишком легко. У нас было две проблемы:

  • анонимный - всегда были проблемы с оператором < return "внутри
  • ловить всегда и все

Итак, я внес некоторые изменения в Try::Tiny, что помогает нам. Теперь мы имеем:

try sub {},
catch 'SomeException' => sub {},
catch [qw/Exception1 Exception2/] => sub {},
catch_all sub {};

Я знаю - этот синтаксис немного экзотичен, но благодаря очевидному "sub" наши программисты теперь знают, что оператор "return" выходит из обработчика исключений, и мы всегда ловим только те исключения, которые хотим поймать:)

  • 1
    Обратите внимание, что вы могли бы использовать sub{} без каких-либо изменений в Try :: Tiny: perl -MTry::Tiny -E"&try(sub { say 'A'; die qq{B\n} if $ARGV[0] }, &catch(sub { print; }));" 1
  • 2
    Но, что еще более важно, обратите внимание, что другие модули (например, TryCatch ) используют реальные блоки, а не подсистемы, избегая шума.
Показать ещё 4 комментария
0

Либо выполните:

local $@;
eval { … }

..., чтобы предотвратить изменение влияния $@на глобальную область видимости или использование Try:: Tiny.

Синтаксически бывают ситуации, когда я предпочитаю один или другой.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню