Кошерно ли присваивать $! в Perl? - PullRequest
6 голосов
/ 25 июня 2009

Можно ли присвоить $! на ошибку в Perl?

Например,

if( ! (-e $inputfile))
{
      $! = "Input file $inputfile appears to be non-existent\n";
      return undef;
}

Таким образом, я могу обрабатывать все ошибки на верхнем уровне.

Спасибо.

Ответы [ 7 ]

12 голосов
/ 25 июня 2009

Если вы присваиваете $ !, он помещается в системную переменную errno, которая принимает только цифры. Таким образом, вы можете сделать:

use Errno "EEXIST";
$! = EEXIST;
print $!;

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

Другая проблема в том, что $! может быть изменен любым системным вызовом. Таким образом, вы можете доверять только тому, чтобы иметь значение, которое вы установили, до тех пор, пока не сделаете печать или что-то еще. Возможно, вам нужна собственная переменная ошибки.

9 голосов
/ 25 июня 2009

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

Вместо этого используйте исключения:

eval { # this ain't the evil eval
   # some code
   die $something;
}
if (my $err = $@) {
   # exception handling
}

Обратите внимание, что вы можете "бросить" или умереть со всем, что вам нужно ..

3 голосов
/ 25 июня 2009

Настройка $! в порядке, но:

  • Вы должны сделать это в конце своей функции
  • вы должны вернуть другое значение, которое указывает, что произошла ошибка
  • вы должны использовать значения errno вашей ОС, а не строки для настройки
  • проверяющий код должен проверить значение, это должно быть сделано немедленно при сбое функции (и только если сбой обозначен функцией)

Следует помнить, что die использует значение в $! для его кода выхода (если он не равен нулю).

3 голосов
/ 25 июня 2009

Мой раввин сказал "нет!"

2 голосов
/ 25 июня 2009

Да, вы можете присвоить вещи (#) $, просто будьте осторожны с тем, где вы это делаете, чтобы не испортить сообщение о некоторых других функциях.

0 голосов
/ 27 июня 2009

$! имеет столько предостережений, поскольку является глобальной переменной, которой назначено множество функций (некоторые из них - функции C, которые вызывает Perl), что я просто выбросил бы исключение (которое в Perl означает смерть) и позволил бы пользователю перехватить его, если им будет интересно. Поэтому вместо того, чтобы писать:

$obj->foo or die $!;
$obj->bar or die $!;
$obj->baz or die $!;

или даже

$obj->foo or die $obj->error;
$obj->bar or die $obj->error;
$obj->baz or die $obj->error;

Вы можете просто написать

$obj->foo;
$obj->bar;
$obj->baz;

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

Если вы хотите игнорировать или исправить ошибку, просто используйте eval BLOCK.

eval { $obj->foo };   # don't care if it works or not
eval { $obj->bar } or do { ...something when it doesn't work... };

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

Примеры этого подхода включают флаг RaiseError DBI , который по умолчанию отключен только для обратной совместимости, и замечательный autodie модуль.

0 голосов
/ 25 июня 2009

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

К счастью, в Perl вы можете помочь. Действительно хорошим решением является использование объектно-ориентированной обработки исключений из Error.pm . Этот модуль позволит вам писать блоки try / catch, например:

try {
    some code;
    code that might thrown an exception;
    more code;
    return;
}
catch Error with {
    my $ex = shift;   # Get hold of the exception object
    # handle the exception;
};

Документация CPAN для модуля довольно хорошая, и на эту тему также есть статья Perl.com .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...