Передача параметров

Информация в подпрограмму и из подпрограммы передается через параметры (аргументы). Для передачи параметров в подпрограмму используется специальный массив @_. Все параметры запоминаются в элементах массива $_[0], $_[1] и т. д. Такой механизм позволяет передавать в подпрограмму произвольное количество параметров.
Массив @_ является локальным для данной подпрограммы, но его элементы — псевдонимы действительных скалярных параметров, и изменение элемента массива @_ вызывает изменение соответствующего действительного параметра.
В языках программирования различают передачу параметров по ссылке и по значению. При передаче параметров по значению подпрограмма получает копию переменной. Изменение копии внутри подпрограммы не влияет на ее оригинал. При передаче параметров по ссылке подпрограмма получает доступ к самой переменной и может ее изменять.
Передача параметров через специальный массив @_ фактически является передачей параметров по ссылке. В языке Perl можно реализовать передачу параметров по значению, если внутри подпрограммы при помощи функции my( ) объявить локальные переменные и присвоить им значения фактических параметров из массива @_, как это сделано в следующем примере (листинг 9.3),
Листинг 9.3. Использование функции mу( ) для передачи параметров по значению
#!/usr/bin/perl
# Передача в подпрограмму параметров по значению 
sub f{
  my($x, $y) = @_;
  return(++$x * --$y);
}
$val = f(9,11);
print "Значение (9+1) * (11-1) равно $val\n";
$x = 9;
$y = 11;
$val = f($x,$y);
print "Значение ($x+1) * ($y-1) равно $val\n";
print "Значение \$х остается равным $x, a \$y равным $y\n";
Результат выполнения:
Значение (9+1) * (11-1) равно 100. 
Значение (9+1) * (11-1) равно 100. 
Значение $x остается равным 9, а $у равным 11.

Передача по ссылке параметров-массивов

Итак, подпрограмма получает и возвращает параметры через специальный массив @_. Если параметр является массивом или хэш-массивом, его элементы также сохраняются в массиве параметров @_. При передаче в подпрограмму нескольких параметров-массивов или хэш-массивов они утрачивают свою целостность. Иными словами, после записи параметров-массивов (хэш-массивов) в массив @_ из него невозможно выделить отдельный параметр-массив (хэш-массив): все параметры в массиве @_ хранятся единой «кучей». Чтобы сохранить при передаче в подпрограмму целостность массива или хэш-массива, следует использовать один из двух основных существующих подходов.
Использование типа typeglob
Первый, более старый, заключается в использовании внутреннего типа данных, называемого typeglob. Принадлежность к типу typeglob обозначается префиксом *. Префикс * можно рассматривать как метасимвол, вместо которого может стоять любой из префиксов $, @, %, &, обозначающих тип данных «скаляр», «массив», «хэш-массив», «функция» соответственно. Интерпретатор преобразует переменную типа typeglob, например *abc, в скалярную величину, которая является ссылкой на гнездо в таблице символов, содержащее элементы разных типов с одинаковым именем abc, и представляет любой из этих элементов. Например, запись *аbс обозначает всю совокупность, а также любую из следующих переменных: скаляр $abc, массив @abc, хэш-массив %abc, функция &abc.
Передача в подпрограмму вместо параметра-массива или хэш-массива соответствующей переменной типа typeglob является имитацией передачи параметра-массива (хэш-массива) по ссылке с сохранением его целостности. Рассмотрим пример из листинга 9.4.
Листинг 9.4. Использование типа typeglob для передачи параметров массивов и хэш- массивов
sub doublargs {
  local (*mylist, *myhash) = @_;
  foreach $item (@mylist) { 
    $item *= 2;
  }
  foreach $key (keys %myhash) {
    $myhash{$key} *= 2;
  }
}
@somelist = (1,2,3);
%somehash = ("one" => 5, "two" => 15, "three" => 20); 
print "начальные значения: \n\@somelist = @somelist\n"; 
foreach $key (keys %somehash) {
  print "\$somehash{$key} = $somehash{$key}";
}
print "\n";
doublargs(*somelist,*somehash);
print "итоговые значения:\n\@somelist = @somelist\n";
foreach $key (keys %somehash) {
  print "\$somehash{$key} = $somehash{$key}";
}
print "\n";
Подпрограмма doublargs принимает на вход массив и хэш-массив и изменяет их элементы, умножая на 2. Вместо массива и хэш-массива в подпрограмму передаются соответствующие переменные типа typeglob, которые легко выделить из массива @_, так как фактически они являются скалярами. Обратите внимание на применение функции local. Использовать вместо нее функцию my( ) здесь нельзя, так как переменная типа typeglob не может быть локальной, она представляет несколько одноименных переменных разных типов из таблицы символов. Далее возникает вопрос, каким образом изменение в подпрограмме массива @mylist влияет на изменение фактического параметра @somelist. Дело в том, что операция присваивания вида *х = *у создает синоним *х для гнезда таблицы символов *у, так что осуществление операции над $х, @х, %х эквивалентно осуществлению этой операции над $у, @y, %у. В результате присваивания
local(*mylist, *myhash) = @_;
создается псевдоним *mylist для *somelist, поэтому все изменения элементов массива @mylist внутри подпрограммы эквивалентны изменениям элементов массива @somelist. Все сказанное справедливо и для хэш-массивов %myhash и %somehash. Результат подтверждает корректность передачи массива и хэш-массива по ссылке:
Начальные значения:
@somelist = l 2 3
$somehash{one} = 5
$somehash{three} = 20
$somehash{two} = 15
Итоговые значения:
@somelist = 2 4 6
$somehash{one} = 10
$somehash{three} = 40
$somehasn{two} = 30
Использование ссылок
Второй способ передачи массивов в подпрограмму заключается в том, чтобы вместо собственно массивов или хэш-массивов передавать ссылки на них. Ссылка является скалярной величиной, и ее легко выделить в массиве параметров @_. Внутри подпрограммы остается только применить к ссылке операцию разыменования для того, чтобы получить доступ к фактическому параметру. Поскольку ссылки появились только в версии Perl 5, то этот способ является относительно новым. При помощи ссылок предыдущий пример можно записать в таком виде, как показано в листинге 9.5.
Листинг 9.5. Использование ссылок для передачи параметров-массивов и хэш-массивов
sub doublparms {
  my ($listref, $hashref) = @_;
  foreach $item (@$listref) { 
    $item *= 2;
  }
  foreach $key (keys %$hashref) {
  $$hashref{$key} *= 2;
  }
}
@somelist = (l,2,3);
%somehash=("one" => 5, "two" => 15, "three" => 20); 
print "начальные значения:\@somelist = @somelist\n"; 
foreach $key (keys %somehash) {
  print "\$somehash{$key} = $somehash{$key}";
}
print "\n";
doublparms(\@somelist,\%somehash);
print "итоговые значения:\n\@somelist = @somelist\n";
foreach $key (keys %somehash) {
  print "\$somehash{$key} = $somehash{$key}";
}
print "\n";
Здесь для описания локальных переменных использована функция my( ). Как мы выяснили ранее в этой главе, применение функции my( ) в подобном случае реализует передачу параметров по значению, то есть их изменение внутри подпрограммы не влияет на фактические параметры. Каким же образом в данном случае осуществляется передача массива и хэш-массива по ссылке? Дело в том, что по значению передаются только ссылки, указывающие на фактические параметры: массив @somelist и хэш-массив %somehash. Используя операции разыменования внутри подпрограммы, мы получаем доступ непосредственно к массиву @somelist и хэш-массиву %somehash и изменяем их элементы. В результате выполнения данного сценария будет выведено:
Начальные значения:
@somelist = 1 2 3
$somehash{one} = 5
$samehash{three} = 20
$somehash{two} = 15
Итоговые значения:
@somelist = 2 4 6
$samehash{one} = 10
$somehash{three} = 40
$somehash{two} = 30

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




2011-06-10 11:32:04 RAM

В последнем листинге в функции ошибка во втором цикле: написано - foceach должно быть - foreach Аналогично при печати итоговых значений.

2011-06-14 20:47:46 Alex

Исправлено, спасибо!




Оставить комментарий:
Ваше Имя:
Email:
Антибот: *  
Ваш комментарий: