Локальные переменные в подпрограммах

Областью видимости, или областью действия, переменной мы будем называть часть программы, где данная переменная может быть использована. В языке Perl, как мы знаем, нет обязательного явного описания переменных. Точкой определения переменной является место, где она впервые встречается в программе. Область действия большинства переменных ограничена пакетам. Исключение составляют некоторые специальные предопределенные глобальные переменные интерпретатора Perl. Пакет — это механизм, позволяющий создать свое пространство имен для некоторого отрезка программы (этот отрезок может включать всю программу). Каждый фрагмент кода Perl-программы относится к некоторому пакету.
Таким образом, переменная, впервые встретившаяся в некоторой подпрограмме, становится доступной во всем пакете, к которому принадлежит данная подпрограмма. Любая переменная в Perl по умолчанию считается глобальной, но эта глобальность ограничена рамками пакета. Иногда бывает необходимо ограничить область действия переменной рамками подпрограммы или блока, в которых она определена. Такие переменные называются локальными. В языке Perl существуют два способа описания локальных переменных: при помощи функций my( ) и local( ).

Функция my( )

Функция my( ) используется для объявления одной или нескольких переменных локальными
my EXPR
и ограничивает их область действия: подпрограммой; заключенным в фигурные скобки блоком операторов; выражением, переданным на выполнение функции eval( ), или файлом, в зависимости от того, в каком месте вызвана для объявления переменных сама функция my ().
Если выражение EXPR содержит список переменных, то он должен быть заключен в скобки:
my ($myvar, @mylist, %myhash);
Одновременно с объявлением переменные могут быть инициализированы:
my $pi = 3.14159;
my ($pi, $exp) = (3.14159, 2.71828);
Переменные, объявленные при помощи функции my( ), доступны в своей области действия только для подпрограмм, определенных в этой области, и недоступны для подпрограмм, определенных за ее пределами. Такие переменные называют лексическими, а саму область видимости — лексической, или статической, областью видимости.
Замыкания
На время вычисления функции формируется ее вычислительное окружение, включающее совокупность действующих переменных с их значениями. После завершения вычисления функции ее вычислительное окружение пропадает, и на него невозможно сослаться позже. Часто бывает полезным, чтобы функция для продолжения вычислений могла запомнить свое вычислительное окружение. В языках программирования существует понятие замыкания, пришедшее из языка Lisp. Это понятие означает совокупность, состоящую из самой функции, как описания процесса вычислений, и ее вычислительного окружения в момент определения функции.
Анонимные процедуры в Perl обладают тем свойством, что по отношению к лексическим переменным, объявленным при помощи функции mу( ), выступают в роли замыканий. Иными словами, если определить анонимную функцию в некоторый момент времени при некоторых значениях лексических переменных, то в дальнейшем при вызове этой функции ей будут доступны значения этих лексических переменных, существовавшие на момент ее определения.
Приведем пример использования этого свойства анонимных функций — числа Фибоначчи.
Последовательностью Фибоначчи называется последовательность чисел, связанных следующими отношениями:
f(l) = 1 
f(2) = 1
f(n) = f(n-l) + f(n-2), n =3, 4, ...
Сравним две подпрограммы, которые можно использовать для вычисления первых N чисел Фибоначчи.
sub fibonacci1 { 
  my $n = shift;
  my $i = 2;
  my ($current, $previous, $preprevious) = (1,1); 
  return 1 if $n <= 2;
  for ( ;  $i < $n; $i++) {
    $preprevious = $previous;
    $previous = $current:
    $current = $previous + $preprevious;
  }
return $current;
}
sub fibonacci2 {
  my ($previous, $preprevious) = (1,1);
  my $current; 
  return sub {
                my $n = shift;
                return 1 if $n <= 2;
                $current = $previous + $preprevious;
                $preprevious = $previous;
                $previous = $current;
             }
}
С использованием функции fibonacci1 для вычисления первых $N чисел Фибоначчи можно использовать следующий цикл:
$N = 15;
for $n (1..$N) {
  print "f($n) = ", fibonacci1($n), "\n";
}
С использованием функции fibonacci2 то же самое можно сделать при помощи следующей последовательности операторов:
$f = fibonacci2( );
for $n (l..$N){
  print "f($n) = ", &$f($n), "\n";
}
Функция fibonacci1(n) вычисляет n-oe число Фибоначчи f(n). Для вычисления n-ого числа Фибоначи надо выполнить n-2 операции сложения, где n >= 3. Таким образом, при использовании функции fibonacci1 для вычисления N первых чисел Фибоначчи необходимо выполнить всего
1 + 2 + ... + N-2 = (N-1)(N-2) / 2
операций сложения.
Функция fibonacci2 возвращает ссылку на анонимную функцию, которая всегда вычисляет только одно, следующее число Фибоначчи на основании двух предыдущих, сохраненных в лексических переменных $previous и $preprevious. Всего для вычисления N первых чисел Фибоначчи с использованием функции fibonacci 2 требуется N-2 операции сложения.

Функция local( )

Функция lосal( ) также используется для объявления и инициализации переменных:
local EXPR;
local ($myvar, @mylist, $myhash);
local $pi = 3.14159;
local ($pi, $exp) = (3.14159, 2.71828);
Но в отличие от функции my( ), она создает не локальные переменные, а временные значения для глобальных переменных внутри: подпрограммы; заключенного в фигурные скобки блока операторов; выражения, переданного на выполнение функции eval( ) или файла, в зависимости от того, в каком месте вызвана для объявления переменных сама функция local( ). Если функция local( ) применяется для описания нескольких переменных, они должны быть заключены в скобки. Если глобальная переменная, объявленная при помощи функции local( ), ранее встречалась до этого объявления и имела некоторое значение, то это значение сохраняется в скрытом стеке и восстанавливается после выхода соответственно из подпрограммы, блока, функции eval( ) или файла. Переменная, объявленная при помощи функции local( ), или, точнее, ее временное значение, доступно для любой функции, вызванной внутри подпрограммы, блока, функции eval( ) или файла, в которых сделано объявление. Такую переменную называют динамической, а ее область видимости — динамической областью видимости, отражая в названии тот факт, что область видимости переменной динамически изменяется с каждым вызовом функции, получающей доступ к этой переменной.
Функция my( ) является более новой, она появилась в версии Perl 5.0. Для создания действительно локальных переменных рекомендуется использовать именно функцию my( ), а не функцию local( ). Впрочем, есть несколько случаев, когда функция my( ) не может заменить функцию local( ).

Следующая страница Содержание главы


Реклама