#perl #scope #eval
Вопрос:
Согласно perldoc, оценка строки должна выполняться в текущей области. Но следующий простой тест, по-видимому, противоречит этому.
Нам нужны следующие два простых файла для настройки теста. Пожалуйста, положите их в одну папку.
test_eval_scope.pm
package test_eval_scope; use strict; use warnings; my %h = (a=gt;'b'); sub f1 { eval 'print %h, "n"'; # print %h, "n"; # this would work # my $dummy = %h; # adding this would also work } 1
test_eval_scope.pl
#!/usr/bin/perl use File::Basename; use lib dirname (__FILE__); use test_eval_scope; test_eval_scope::f1();
Когда я запускаю программу, я получаю следующую ошибку
$ test_eval_scope.pl Variable "%h" is not available at (eval 1) line 1.
Мой вопрос в том, почему переменная %h выходит за рамки.
Я внес некоторые изменения и обнаружил следующее:
- Если я запущу без eval(), как в приведенном выше комментарии, это сработает. это означает, что %h должен быть в области видимости.
- Если я просто добавлю, казалось бы, бесполезное упоминание в коде, как в приведенном выше комментарии, eval() тоже будет работать.
- Если я объединю файл pl и pm в один файл, eval() тоже будет работать.
- Если я объявлю %h с «нашим» вместо «моего», eval() тоже будет работать.
Я столкнулся с этим вопросом, когда писал большую программу, которая анализировала пользовательский код во время выполнения. Мне не нужны решения, так как у меня есть множество обходных путей выше. Но я не могу объяснить, почему приведенный выше код не работает. Это влияет на мою гордость за perl.
Моя версия perl-v5.26.1 в Linux.
Спасибо вам за вашу помощь!
Ответ №1:
Подлодки фиксируют только переменные, которые они используют. Поскольку f1
он не используется %h
, он не захватывает его и %h
становится недоступным f1
после того, как он выходит за рамки, когда модуль завершает выполнение.
Любая ссылка на var, в том числе оптимизированная, приводит к тому, что подменю захватывает переменную. Таким образом, работает следующее:
sub f1 { %h if 0; eval 'print %h, "n"'; }
ДЕМОНСТРАЦИЯ:
$ perl -M5.010 -we' { my $x = "x"; sub f { eval q{$x} } sub g { $x if 0; eval q{$x} } } say "f: ", f(); say "g: ", g(); ' Variable "$x" is not available at (eval 1) line 1. Use of uninitialized value in say at -e line 8. f: g: x
Комментарии:
1. оптимизация, по-видимому, является ключевым фактором.
2. Это не просто оптимизация; она позволяет своевременно уничтожать переменные.