На этом шаге мы рассмотрим использование рекурсивных подпрограмм.
Язык Perl допускает, чтобы подпрограмма вызывала саму себя. Такая подпрограмма называется рекурсивной. При написании рекурсивных подпрограмм следует иметь в виду, что все переменные, значения которых изменяются внутри подпрограммы, должны быть локальными, т.е. объявленными при помощи функций my() или local(). В этом случае при каждом вызове подпрограммы создается новая копия переменной. Это позволяет избежать неопределенности и замещения текущего значения переменной ее значением из следующего вызова подпрограммы.
Рекурсивные подпрограммы следует применять осторожно. Многие алгоритмы, являющиеся по сути итеративными, можно реализовать при помощи рекурсивной подпрограммы. Однако такая подпрограмма окажется неэффективной по времени выполнения и потребляемым ресурсам памяти. Вместе с тем, существуют задачи, решить которые можно только при помощи рекурсивных алгоритмов. В этом случае применение рекурсивных подпрограмм является не только вполне оправданным, но и необходимым. Одной из таких задач, которую операционная система решает постоянно, является рекурсивный просмотр дерева каталогов. Рассмотрим пример рекурсивной Perl-подпрограммы tree(), которая делает то же самое: просматривает дерево каталогов, начиная с каталога, заданного параметром подпрограммы, и выводит список файлов, содержащихся в каждом подкаталоге.
#! perl -w
sub tree
{
local (*ROOT);
my ($root)=$_[0];
opendir ROOT, $root;
my (@filelist) = readdir ROOT;
closedir ROOT;
for $x (@filelist)
{
if ($x ne "." and $x ne "..")
{
$x=$root."/".$x;
print " $x\n" if (-f $x) ;
if (-d $x)
{
print "$x:\n";
tree($x);
}
}
}
}
Здесь использованы встроенные подпрограммы Perl opendir(), closedir(), readdir(), применяемые соответственно для открытия каталога, его закрытия и чтения содержимого. Подпрофамма tree() рекурсивно просматривает каталог, переданный ей в качестве параметра, и выводит имена вложенных подкаталогов и содержащихся в них файлов в следующем виде:
/home/httpd/cgi-bin: /home/httpd/html: /home/httpd/html/index.html /home/httpd/html/manual: /home/httpd/html/manual/LICENSE /home/httpd/html/manual/bind.html /home/httpd/html/manual/cgi_path.html . . . .
На следующем шаге мы рассмотрим несколько примеров использования изученного материала.