- Вы можете хранить анонимные подпрограммы в массивах, хешах и скалярах.
- Вы можете построить их во время выполнения
- Вы можете передавать их в качестве аргументов другим функциям.
- Вы можете хранить переменные в окружающей области видимости.
Последний пункт, пожалуй, самый важный, потому что это часто самый неожиданный аспект именованных и анонимных подпрограмм в Perl. Пример:
sub outer
{
my $a = 123;
sub inner
{
print $a, "\n";
}
# At this point, $a is 123, so this call should always print 123, right?
inner();
$a = 456;
}
outer(); # prints 123
outer(); # prints 456! Surprise!
Но изменить «внутренний» с именованной подпрограммы на ссылку на анонимную подпрограмму, и это работает, - гораздо менее удивительный способ:
sub outer
{
my $a = 123;
my $inner = sub
{
print $a, "\n";
};
# At this point, $a is 123, and since the anonymous subrotine
# whose reference is stored in $inner closes over $a in the
# "expected" way...
$inner->();
$a = 456;
}
# ...we see the "expected" results
outer(); # prints 123
outer(); # prints 123
(Конечно, ожидания у всех разные, поэтому «пугающие цитаты» вокруг «ожидаемые».)
Вот пример использования в реальном коде (хотя следует отметить, что интерфейс File::Find
обычно считается плохим - из-за использования глобальных переменных, а не использования анонимных подпрограмм):
sub find_files
{
my @files;
my $wanted = sub
{
if($something)
{
push @files, $File::Find::name;
}
};
# The find() function called here is imported from File::Find
find({ wanted => $wanted }, $directory);
return @files;
}
Передача именованной подпрограммы в качестве значения параметра wanted
потребует загрязнения пространства имен подпрограммой, которую можно использовать только один раз, и определения именованной подпрограммы в подпрограмме find_files()
. «неожиданное» поведение, продемонстрированное ранее.