WedX - журнал о программировании и компьютерных науках

Как лучше всего поступить, если в коде Perl что-то пойдет не так?

Возможные дубликаты:
Как могу ли я аккуратно обработать проверку ошибок в Perl?
Что не так в исключениях в Perl?

Я видел код, который работает так:

do_something($param) || warn "something went wrong\n";

и я также видел такой код:

eval {
  do_something_else($param);
};
if($@) {
  warn "something went wrong\n";
}

Должен ли я использовать eval / die во всех моих подпрограммах? Должен ли я писать весь свой код на основе данных, возвращаемых подпрограммами? Разве код (снова и снова) не замедляет меня?


  • притвориться, что это написал кто-то другой? ;) 07.03.2010
  • Ага :). Довольно сложно, когда написано Автор: Гео. :) 07.03.2010
  • Подробное обсуждение исключений в perl см. В разделе stackoverflow.com/questions/2165161/ 07.03.2010
  • Используйте твердые стальные каркасы для серверных стоек, чтобы взрыв от взрыва ЦП не уничтожил целый квартал. 08.03.2010

Ответы:


1

Блок eval не является строкой eval, поэтому нет, он не медленный. Однозначно рекомендуется использовать его.

Однако есть несколько раздражающих тонкостей в том, как это работает (в основном раздражающие побочные эффекты того факта, что $@ является глобальной переменной), поэтому рассмотрите возможность использования Попробуйте :: Tiny вместо запоминания всех маленьких уловок, которые нужно использовать eval в защите.

07.03.2010

2
do_something($param) || warn "something went wrong\n";

В этом случае ожидается, что do_something вернет код ошибки, если что-то пойдет не так. Либо он не может умереть, либо это действительно необычная ситуация.

eval {
  do_something_else($param);
};
if($@) {
  warn "something went wrong\n";
}

Здесь предполагается, что единственный механизм, с помощью которого do_something_else сообщает о том, что что-то идет не так, - это создание исключений.

Если do_something_else вызывает исключения в действительно исключительных ситуациях и возвращает значение ошибки в некоторых других, вам также следует проверить его возвращаемое значение.

Использование блочной формы eval не вызывает дополнительной компиляции во время выполнения, поэтому нет серьезные недостатки производительности:

Во второй форме код в BLOCK анализируется только один раз - в то же время, когда анализируется код, окружающий сам eval, - и выполняется в контексте текущей Perl-программы. Эта форма обычно используется для более эффективного перехвата исключений, чем первая (см. Ниже), а также дает возможность проверки кода в BLOCK во время компиляции.

07.03.2010

3

Модули, которые warn очень раздражают. Либо получится, либо проиграет. Не выводите что-либо на терминал, а затем продолжайте работать; моя программа не может принять меры на основании какого-то сообщения, которое вы напечатали. Если программа может продолжать работать, печатайте сообщение только в том случае, если вам явно сказали, что все в порядке. Если программа не может продолжать работу, die. Вот для чего это нужно.

Всегда генерируйте исключение, когда что-то не так. Если вы можете решить проблему, исправьте ее. Если вы не можете решить проблему, не пытайтесь; просто создайте исключение и позвольте вызывающей стороне разобраться с этим. (И если вы не можете обработать исключение из того, что вы вызываете, не делайте этого.)

По сути, причина того, что многие программы содержат ошибки, заключается в том, что они пытаются исправить ошибки, которые у них не получается. Программу, которая умирает без ошибок при первых признаках проблемы, легко отладить и исправить. Программа, которая продолжает работать, даже если она запуталась, просто портит данные и всех раздражает. Так что не делай этого. Умри как можно скорее.

08.03.2010

4

Ваши два примера делают совершенно разные вещи. Первый проверяет ложное возвращаемое значение и предпринимает некоторые действия в ответ. Второй проверяет фактическую смерть вызываемого кода.

Вам нужно будет решить для себя, какое действие уместно в каждом конкретном случае. Я бы посоветовал просто вернуть false в большинстве случаев. Вы должны явно dieing только в том случае, если вы столкнулись с настолько серьезными ошибками, что вы не можете продолжить (или нет смысла продолжать, но даже в этом случае вы все равно можете вернуть false).

Оборачивание блока в eval {} - это не то же самое, что перенос произвольного кода в eval "". В первом случае код все еще анализируется во время компиляции, и вы не несете никаких дополнительных накладных расходов. Вы просто поймаете любую смерть этого кода (но у вас не будет никаких указаний относительно того, что пошло не так или как далеко вы продвинулись в своем коде, за исключением значения, которое осталось для вас в $@). В последнем случае код обрабатывается интерпретатором Perl как простая строка до тех пор, пока он не будет фактически оценен, поэтому здесь есть определенная стоимость при вызове интерпретатора (и вы теряете все проверки вашего кода во время компиляции).

Между прочим, способ, которым вы вызвали eval и проверил значение $@, не является рекомендуемой формой; подробное обсуждение ошибок и приемов исключений в Perl см. в этом обсуждении.

07.03.2010
  • Когда я возвращаю false, как мне также выдавать сообщение об ошибке? 07.03.2010
  • @Geo: вы можете вывести строку в stderr с помощью warn() или записать сообщение, используя утилиту ведения журнала (например, Log :: Log4perl). 07.03.2010

  • 5

    Первая версия очень «перлиша» и довольно проста для понимания. Единственный недостаток этой идиомы в том, что она читается только в кратких случаях. Если обработка ошибок требует большей логики, используйте вторую версию.

    07.03.2010

    6

    На самом деле никто еще не обратился к части «передовой практики», поэтому я перейду к ней.

    Да, вы должны определенно генерировать исключение в своем коде, когда что-то пойдет не так, и вы должны сделать это как можно раньше (чтобы вы ограничили код, который необходимо отлаживать, чтобы выяснить, что его вызывает) .

    Код, который делает такие вещи, как return undef для обозначения сбоя, не особенно надежен просто потому, что люди будут использовать его, не проверяя возвращаемое значение undef - это означает, что переменная, которую они предполагают, имеет что-то значимое, на самом деле может не иметь. Это приводит к сложным, трудно поддающимся отладке проблемам и даже неожиданным проблемам, возникающим позже в ранее работающем коде.

    Более надежный подход - написать свой код так, чтобы он умирал, если что-то пойдет не так, а затем только если вам нужно восстановиться после этого сбоя, оберните все вызовы к нему в eval{ .. } (или, лучше, try { .. } catch { .. } из Try :: Tiny, как уже упоминалось). В большинстве случаев вызывающий код не может сделать ничего значимого для восстановления, поэтому вызывающий код в общем случае остается простым, и вы можете просто предположить, что получите обратно полезное значение. Если что-то пойдет не так, вы получите сообщение об ошибке из фактической части кода, которая завершилась ошибкой, вместо того, чтобы молча получить undef. Если ваш вызывающий код может что-то сделать для восстановления сбоев, он может организовать перехват исключений и делать все, что ему нужно.

    Стоит прочитать о классах исключений, которые представляют собой структурированный способ отправки дополнительных информация для вызывающего кода, а также позволяет ему выбирать, какие исключения он хочет перехватить, а какие не может обработать. Вы, вероятно, не захотите использовать их повсюду в своем коде, но они полезны, когда у вас есть что-то сложное, которое может выходить из строя одинаково сложным образом, и вы хотите, чтобы сбои можно было исправить.

    08.03.2010
    Новые материалы

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

    ИИ в аэрокосмической отрасли
    Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


    Для любых предложений по сайту: [email protected]