Каковы общие ловушки, связанные с 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 Ошибка неудачного запроса:...