Нет.
Это не оптимизация; переменная была создана, но она просто перестала существовать к тому времени, когда вы решили проверить ее, потому что выполнение достигло своей области.
В случае, когда подпрограмма видит $x
, потому что она использует $x
, это потому что саб захватил $x
. Подпрограммы захватывают только те переменные, которые им нужны. Захват без необходимости может иметь очень пагубные последствия (потому что деструкторы не будут вызываться, когда ожидается).
Невозможно сказать Perl делать иначе, кроме как по переменным.
Прежде всего, код, который вы разместили, не демонстрирует описанную вами проблему.
$ perl -d a.pl
Loading DB routines from perl5db.pl version 1.55
Editor support available.
Enter h or 'h h' for help, or 'man perldebug' for more help.
main::(a.pl:1): my $x = 77;
DB<1> r
main::test(a.pl:5): 1;
DB<1> x $x
0 77
DB<2> q
Но у вас возникла бы эта проблема, если бы код был частью модуля.
Foo.pm
:
package Foo;
my $x = 77;
sub test {
$DB::single = 1;
1;
}
1;
$ perl -d -I. -e'use Foo; Foo::test()'
Loading DB routines from perl5db.pl version 1.55
Editor support available.
Enter h or 'h h' for help, or 'man perldebug' for more help.
main::(-e:1): use Foo; Foo::test()
DB<1> r
Foo::test(Foo.pm:7): 1;
DB<1> x $x
0 undef
DB<2> q
В будущем, пожалуйста, убедитесь, что опубликованный вами код действительно демонстрирует проблему, о которой вы заявляете.
Скажите, что у вас было
{
my $x = 77;
}
CORE::say $x;
Это не работает, верно? Это не из-за оптимизации - $x
был создан, и ему было присвоено 77
, - это потому, что $x
прекратил свое существование, когда вышла лексическая область, которая его заключала.
Теперь давайте рассмотрим следующее:
{
my $x = 77;
sub get_x { $x }
}
CORE::say get_x();
Это как-то печатает 77
. Как это возможно? Я только что объяснил, что $x
прекратил свое существование до достижения последней строки. Ну, он бы прекратил свое существование, если бы get_x
не захватил его. Мы говорим, что get_x
является замыканием . $x
продолжает существовать, но только в закрытии.
Нет необходимости говорить, что для захвата переменной требуются усилия (процессор и память), поэтому захватываются только те переменные, которые должны быть захвачены. Не захватывать переменные, которые не нужно фиксировать, не является оптимизацией; он просто не выполняет работу, о которой не просили.
Какое отношение это имеет к вашему вопросу? Ну, блоки (кудри) не единственные вещи, которые создают лексические рамки. Файлы, загруженные Perl, выполняются в лексической области fre sh.
Другими словами, вышеприведенный тест на неудачу примерно эквивалентен
BEGIN {
package Foo;
my $x = 77;
sub test {
$DB::single = 1;
1;
}
$INC{"Foo.pm"} = 1;
}
use Foo;
Foo::test();
И сводится к
{
my $x = 77;
sub test {
$DB::single = 1;
1;
}
}
test();
Учитывая вышесказанное, эффективно задается следующий вопрос:
Есть ли способ сообщить Perl, что переменные захвата подчиненных элементов не нужны? не используете?
Ответ - нет.
Только подчиненная переменная и все еще существующие переменные доступны для подпрограммы при ее вызове. Захват ненужных переменных приведет к тому, что переменные будут продолжать существовать дольше, чем ожидалось, что означает, что деструкторы не будут вызываться, когда ожидается.
Нет способа указать Perl делать иначе, кроме как по переменной за переменной основе (например, добавив $x if 0;
к подпункту).
Приложение: Вы можете столкнуться с подобными проблемами с eval EXPR
.
$ perl -e'
my $x = 77;
sub test {
return eval($_[0]);
}
printf "[%s]\n", test(q{$x});
'
[77]
$ perl -e'
{
my $x = 77;
sub test {
return eval($_[0]);
}
}
printf "[%s]\n", test(q{$x});
'
[]
$ perl -e'
{
my $x = 77;
sub test {
$x if 0;
return eval($_[0]);
}
}
printf "[%s]\n", test(q{$x});
'
[77]
Приложение: Захваты очень полезный! Они делают обратные вызовы бризом.
sub any {
my $callback = shift;
for (@_) {
return 0 if $callback->();
}
return 1;
}
my %bad = map { $_ => 1 } qw( foo bar );
die if any(sub { $bad{$_} }, @args); # Captures %bad