{
sub a {
print 1;
}
}
a;
Ошибка, не так ли?
a
не должен быть доступен снаружи.
Работает ли он в Perl 6 *?
* Извините, что я еще не установил его.
{
sub a {
print 1;
}
}
a;
Ошибка, не так ли?
a
не должен быть доступен снаружи.
Работает ли он в Perl 6 *?
* Извините, что я еще не установил его.
Вы спрашиваете, почему sub видимо вне блока? Если это так, то из-за того, что ключевое слово sub
времени компиляции помещает sub в пространство имен main
(если вы не используете ключевое слово package
для создания нового пространства имен). Вы можете попробовать что-то вроде
{
my $a = sub {
print 1;
};
$a->(); # works
}
$a->(); # fails
В этом случае ключевое слово sub
не создает sub и помещает его в пространство имен main
, а вместо этого создает анонимную подпрограмму и сохраняет ее в переменной с лексической областью. Когда переменная выходит за пределы области видимости, она больше не доступна (обычно).
Чтобы узнать больше, perldoc perlsub
Кроме того, знаете ли вы, что вы можете проверить, как Perl-парсер видит ваш код? Запустите perl с флагом -MO=Deparse
, как в perl -MO=Deparse yourscript.pl
. Ваш исходный код анализирует как:
sub a {
print 1;
}
{;};
a ;
Сначала скомпилируется sub, затем блок запускается без кода в нем, затем вызывается a
.
Для моего примера в Perl 6 см. Успех, Отказ. Обратите внимание, что в Perl 6 разыменование .
не ->
.
Изменить: Я добавил еще один ответ о новой экспериментальной поддержке лексических подпрограмм, ожидаемых для Perl 5.18.
В Perl 6 субсайты действительно лексически охвачены, поэтому код вызывает ошибку (как уже указывали несколько человек).
Это имеет несколько интересных последствий:
Подпрограммы - это область с областью действия, но не с областью охвата.
#!/usr/bin/perl
use strict;
use warnings;
package A;
sub a {
print 1, "\n";
}
a();
1;
package B;
sub a {
print 2, "\n";
}
a();
1;
Именованные подпрограммы в Perl создаются как глобальные имена. В других ответах показано, как создавать лексические подпрограммы, назначая анонимный субрежим лексической переменной. Другой вариант - использовать переменную local
для создания поддиапазона с динамической областью.
Основные отличия между ними - стиль вызова и видимость. Поддиапазон с динамической областью может быть назван как именованный элемент sub, и он также будет глобально отображаться до тех пор, пока не будет определен блок, в котором он определен.
use strict;
use warnings;
sub test_sub {
print "in test_sub\n";
temp_sub();
}
{
local *temp_sub = sub {
print "in temp_sub\n";
};
temp_sub();
test_sub();
}
test_sub();
Это должно печатать
in temp_sub
in test_sub
in temp_sub
in test_sub
Undefined subroutine &main::temp_sub called at ...
Если вы видите компиляцию кода, запустите и распечатаете "1", вы не будете испытывать ошибку.
Кажется, вы ожидаете, что подпрограммы будут только вызываемыми внутри лексической области, в которой они определены. Это было бы плохо, потому что это означало бы, что нельзя будет вызывать подпрограммы, определенные в других файлах. Может быть, вы не понимали, что каждый файл оценивается в своей лексической области? Это позволяет использовать
my $x = ...;
sub f { $x }
Из-за риска очередного ругани @tchrist, я добавляю еще один ответ для полноты. Ожидается, что Perl 5.18 будет включать лексические подпрограммы в качестве экспериментальной функции.
Вот ссылка на соответствующую документацию. Опять же, это очень экспериментально, его нельзя использовать для производственного кода по двум причинам:
Так что играйте с этой новой игрушкой, если хотите, но вас предупредили!
Да, я думаю, что это дефект дизайна - более конкретно, первоначальный выбор использования динамического охвата, а не лексического охвата, сделанного в Perl, что естественно приводит к такому поведению. Но не все разработчики языков и пользователи согласятся. Таким образом, вопрос, который вы задаете, не имеет четкого ответа.
Лексическая область была добавлена в Perl 5, но в качестве дополнительной функции вам всегда нужно указать ее конкретно. С этим выбором дизайна я полностью согласен: обратная совместимость важна.