# определение подпрограммы с 1-м параметром-скаляром
sub list_mp3 ($) {
my $path = $_[0];
# ...
}
# определение подпрограммы c 2-мя скалярными параметрами
sub translate ($$@) { # и списком скаляров
my ($from_lang, $to_lang, @words) = @_;
# ...
}
sub generate_test(); # объявление подпрограммы без параметров
Для подпрограмм, определенных с прототипами, компилятор контролирует количество передаваемых аргументов и устанавливает ожидаемый подпрограммой контекст для каждого из аргументов. В приведенном далее вызове подпрограммы вместо массива ей будет передано количество элементов массива, поскольку прототип подпрограммы устанавливает скалярный контекст для единственного аргумента:
list_mp3 @dirs; # будет передан 1 скаляр: scalar @dirs
Перечень символов, применяемых для описания прототипов, с примерами определения подпрограмм приведен в таблице 12.1.
Таблица 12.1. Обозначение прототипов подпрограмм
Прототип | Требования к параметрам | Пример определения / описания | Пример вызова |
---|---|---|---|
() | отсутствие аргументов | sub mytime () | mytime; |
$ | скалярное значение | sub myrand ($) sub myrename ($$) | myrand 100; myrename $old, $new; |
@ | список скалярных значений (поглощает остальные параметры, поэтому употребляется последним в списке) | sub myreverse (@) sub myjoin ($@) | myreverse $a, $b, $c; myjoin ':', $x, $y, $z; |
& | подпрограмма | sub mygrep (&@) | mygrep {/pat/} $a, $b, $c; |
* | элемент таблицы символов (например, дескриптор файла) | sub myopen (*$) | myopen HANDLE, $name; |
\ | взятие ссылки на следующий за ней прототип | sub mykeys (\%) sub mypop (\@) sub mypush(\@@) | mykeys %hash; mypop @array; mypush @stack, $a, $b; |
; | разделитель обязательных параметров от необязательных (в конце списка) | sub mysubstr ($$;$) | mysubstr $str, $pos; mysubstr $str, $pos, $length; |
Проверки на соответствие прототипам не выполняются, если подпрограмма вызывается устаревшим способом (с префиксом &), а также для методов и подпрограмм, вызываемых через ссылки.
Скалярные переменные могут хранить ссылки не только на данные, но и на подпрограммы. В операции взятия ссылки имя подпрограммы должно использоваться с разыменовывающим префиксом &, как это показано в следующем примере:
$ref2max = \&max; # взятие ссылки на подпрограмму
sub max { # вычисляет максимум из списка значений
my $maximum = shift;
foreach (@_) { $maximum = $_ if ($_ > $maximum); }
return $maximum;
}
print ref($ref2max); # будет выведено: CODE
Первый способ обращения к подпрограмме через ссылочную переменную оформляется аналогично обращению к элементу массива или хэша: после имени переменной, содержащей ссылку на подпрограмму, записывается операция разыменования ссылки (->), за которой обязательно указываются круглые скобки (со списком аргументов или без него), которые показывают, что это обращение к подпрограмме:
$max_of_list = $ref2max->(@list_of_numbers);
Другая форма обращения к подпрограмме с использованием ссылочной переменной предполагает использование префикса &:
$max_of_list = &$ref2max(@list_of_numbers);
# можно окружить ссылочную переменную фигурными скобками
$max_of_list = &{$ref2max}(@list_of_numbers);
Вызов подпрограммы без параметров в этом случае можно записывать без круглых скобок, а при использовании -> скобки обязательны (иначе как узнать, что это обращение к подпрограмме?):
&$reference_to_procedure; # с префиксом подпрограмм
$reference_to_procedure->(); # с операцией разыменования
Если предполагается, что доступ к подпрограмме будет происходить не по имени, а только по ссылке, то можно определить анонимную подпрограмму и присвоить ссылку на нее в скалярную переменную, через которую будет осуществляться вызов подпрограммы.
my $ref2sum = sub { # определение анонимной подпрограммы
my $sum = 0; # вычисляет сумму списка значений
$sum += $_ foreach (@_);
return $sum;
}; # конец операции присваивания переменной $ref2sum
print $ref2sum->(1..5), " \n";
Ссылки на подпрограммы бывает удобно хранить в массивах, например, когда над одними и теми же данными нужно выполнить целый список преобразований. Примерно так:
my @refs = ($ref2read, $ref2calc, $ref2format);
for (my $i = 0; $i < @refs; $i++) {
@data = $refs[$i]->(@data); # обработать данные
}
В других случаях ссылки на подпрограммы предпочтительнее поместить в хэш, чтобы в каждом его элементе подпрограмма ассоциировалась с нужным поисковым ключом. Как в этом примере: