Передача параметров Информация в подпрограмму и обратно передается через параметры (аргументы). Для передачи параметров в подпрограмму используется специальный массив @_. Все параметры запоминаются в элементах массива $_ [ 0 ], $_ [ 1 ] и т. д. Такой механизм позволяет передавать в подпрограмму произвольное количество параметров. Массив @_ является локальным для данной подпрограммы, но его элементы — это псевдонимы действительных скалярных параметров. Изменение элемента массива @_ вызывает изменение соответствующего действительного параметра. В языках программирования различают передачу параметров по ссылке и по значению. При передаче параметров по значению подпрограмма получает копию переменной. Изменение копии внутри подпрограммы не влияет на ее оригинал. При передаче параметров по ссылке подпрограмма получает доступ к самой переменной и может ее изменять. Передача параметров через специальный массив @_ фактически является передачей параметров по ссылке. В языке Perl можно реализовать передачу параметров по значению, если внутри подпрограммы при помощи функции ту о объявить локальные переменные и присвоить им значения фактических параметров из массива @_, как это сделано в следующем примере. #!/usr/bin/perl # Передача в подпрограмму параметров по значению sub f { my($x, $y) = @_; return (++$х * —$у); } $val = f ^lib-print "Значение (9+1) * (11-1) равно $val.\n"; $х = 9; $У = 11; $val = f($x,$y); print "Значение ($х+1) * ($у-1) равно $val.\n"; print "Значение \$х остается равным $х, а \$у равным $у.\п"; Результат выполнения: Значение (9+1) * (11-1) равно 100. Значение (9+1) * (11-1) равно 100. Значение $х остается равным 9, а $у равным 11. Передача по ссылке параметров-массивов Итак, подпрограмма получает и возвращает параметры через специальный массив @_. Если параметр является массивом или хеш-массивом, его элементы также сохраняются в массиве параметров @_. При передаче в подпрограмму нескольких параметров-массивов или хеш-массивов они утрачивают свою целостность. Иными словами, после записи параметров-массивов (хеш-массивов) в массив @_ из него невозможно выделить отдельный параметр-массив (хеш-массив): все параметры в массиве @_ хранятся единой "кучей". Для сохранения при передаче в подпрограмму целостности массива или хеш-массива существуют два основных подхода. Использование типа typeglob Первый подход, более старый, заключается в использовании внутреннего типа данных, называемого typeglob. Принадлежность к типу typeglob обозначается префиксом "*". Префикс "*" можно рассматривать как метасимвол, вместо которого может стоять любой из префиксов "$", "@", "%", "&", обозначающих тип данных "скаляр", "массив", "хеш-массив", "функция" соответственно. Интерпретатор преобразует переменную типа typeglob, например, *abc, в скалярную величину. Эта величина является ссылкой на гнездо в таблице символов, содержащее элементы, разных типов с одинаковым именем abc, и представляет любой из этих элементов. Например, запись *abc обозначает всю совокупность, а также любую из следующих переменных: скаляр $abc, массив @abc, хеш %abc, функция sabc. (Таблицы символов обсуждаются в части 12 ) Передача в подпрограмму вместо параметра-массива или хеш-массива соответствующей переменной типа 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"; Подпрограмма doubiargs принимает на вход массив и хеш-массив и изменяет их элементы, умножая на 2. Вместо массива и хеш-массива в подпрограмму передаются соответствующие переменные типа typeglob, которые легко выделить из массива @_, так как фактически они являются скалярами. Обратите внимание на применение функции local. Использовать вместо нее функцию ту здесь нельзя. Переменная типа typeglob не может быть локальной, она представляет несколько одноименных переменных разных типов из таблицы символов. Далее возникает вопрос, каким образом изменение в подпрограмме массива @myiist влияет на изменение фактического параметра gsomeiist. Дело в том, что операция присваивания вида *х = *у создает синоним *х для гнезда таблицы символов *у, так что осуществление операции над $х, @х, %х эквивалентно осуществлению этой операции над $у, @у, %у. В результате присваивания local(*mylist, *myhash) = @_; создается псевдоним *myiist для *someiist, поэтому все изменения элементов массива @myiist внутри подпрограммы эквивалентны изменениям элементов массива @someiist. Все сказанное справедливо и для хеш-массивов %myhash и %somehash. Результат подтверждает корректность передачи массива и хеш-массива по ссылке: начальные значения: @somelist=l 2 3 $somehash{one}=5 $somehash{three}=20 $somehashftwo)=15 итоговые значения: @somelist=2 4 6 $somehash{one}=10 $somehash(three}=40 $somehash{two}=30 Использование ссылок Второй, более новый способ передачи массивов в подпрограмму заключается в том, чтобы вместо собственно массивов или хеш-массивов передавать ссылки на них. Ссылка является скалярной величиной и ее легко выделить в массиве параметров @_. Внутри подпрограммы остается только применить к ссылке операцию разыменования для того, чтобы получить доступ к фактическому параметру. Поскольку ссылки появились только в версии Perl 5, то этот способ является относительно новым. При помощи ссылок предыдущий пример можно записать в следующем виде, sub doublparms { ray ($listref, $hashref) = @_; foreach $item (@$listref} { $item *= 2; } . foreach $key (keys %$hashref) { $$hashref{$key} *= 2; } } @somelist=(1,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"; Здесь для описания локальных переменных использована функция ту. Как мы выяснили ранее в этой главе, применение функции ту в подобном случае реализует передачу параметров по значению. Другими словами, их изменение внутри подпрограммы не влияет на фактические параметры. Каким же образом в данном случае осуществляется передача массива и хеш-массива по ссылке? Дело в том, что по значению передаются только ссылки, указывающие на фактические параметры: массив @someiist и хеш-массив %somehash. Используя операции разыменования внутри подпрограммы, мы получаем доступ непосредственно к массиву @someiist и хеш-массиву %somehash, и изменяем их элементы. В результате выполнения данного сценария будет выведено: начальные значения: @somelist=1 2 3 $somehash{one}=5 $somehash{three}=20 $somehash{two}=15 итоговые значения: @somelist=2 4 6 $somehash{one}=10 $somehash{three)=40 $somehash{two}=30 Поделитесь этой записью или добавьте в закладки | Полезные публикации |