Каковы общие ловушки, связанные с Perl eval, что может заставить вас выбрать модуль, например Try::Tiny?
Каковы общие ошибки при использовании Perl eval?
Ответ 1
Perl eval поставляется в двух вариантах: string eval и block eval. String eval вызывает компилятор для выполнения исходного кода. Блок eval окружает уже скомпилированный код в оболочке, которая будет захватывать исключение die. (строка eval также вызывает исключение die, а также любые ошибки компиляции).
Try:: Tiny применим только к блочной форме eval, но для обеих форм применяется следующее.
При каждом вызове eval он изменит значение [email protected]. Это будет либо '', если eval преуспел, либо ошибка, улавливаемая eval.
Это означает, что каждый раз, когда вы вызываете eval, вы удаляете все предыдущие сообщения об ошибках. Try::Tiny локализует переменную [email protected] для вас, так что успешный eval не очистит сообщение предыдущей неудачной оценки.
Другая ошибка связана с использованием [email protected] в качестве проверки, чтобы определить, удалось ли eval. Общий шаблон:
eval {...};
if ([email protected]) {
# deal with error here
}
Это зависит от двух предположений: во-первых, любое сообщение об ошибке [email protected] может содержать истинное значение (обычно true) и что между блоком eval и оператором if нет кода.
Визуально, конечно, последнее верно, но если блок eval создал объект, и этот объект вышел из области действия после того, как eval не удался, тогда метод DESTROY будет вызываться перед оператором if. Если DESTROY вызывает вызов eval без локализации [email protected], и он успешно завершается, то к моменту выполнения вашего оператора if переменная [email protected] будет удалена.
Решение этих проблем:
my $return = do {
local [email protected];
my $ret;
eval {$ret = this_could_fail(); 1} or die "eval failed: [email protected]";
$ret
};
Разрыв строки за строкой, local [email protected] создает новый [email protected] для блока do, который предотвращает слияние предыдущих значений. my $ret будет возвратным значением оцененного кода. В блоке eval назначается $ret, а затем блок возвращает 1. Таким образом, независимо от того, что, если eval удастся, оно вернет true, и если оно не получится, оно вернет false. Это зависит от вас, что делать в случае неудачи. Вышеупомянутый код просто умирает, но вы можете легко использовать возвращаемое значение блока eval для принятия решения о запуске другого кода.
Поскольку вышеупомянутое заклинание немного утомительно, оно становится склонным к ошибкам. Использование модуля типа Try::Tiny изолирует вас от этих потенциальных ошибок за счет нескольких вызовов функций на каждый eval. Важно знать, как правильно использовать eval, потому что Try::Tiny не поможет вам, если вам нужно использовать строку eval.
Ответ 2
Проблемы объясняются в Try:: Tiny documentation. Вкратце, это:
Ответ 3
В дополнение к ответам выше, я бы добавил...
- На eval влияет глобальный обработчик
$SIG{__DIE__}, вызывающий действие на расстоянии. - Для новичков легко путать
eval BLOCKиeval STRING, так как они, похоже, делают то же самое, но одно - это дыра в безопасности.
Попробуйте:: У Tiny есть свои ловушки, самое большое существо, что, хотя он выглядит как блок, на самом деле это вызов подпрограммы. Это означает:
eval {
...blah blah...
return $foo;
};
и это:
try {
...blah blah...
return $foo;
};
не делают то же самое. Они представлены в разделе CAVEATS в файлах Try:: Tiny. Тем не менее, я бы рекомендовал его более eval.
Ответ 4
Использование eval в функции X11 может остаться не в состоянии.
Код похож на
eval {
@win_arrays = GetWindowsFromPid($pid);
};
script будет выведен из
X Ошибка неудачного запроса:...