Ответ 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.