Чтение онлайн

ЖАНРЫ

Язык программирования Perl

Шохирев Михаил Васильевич

Шрифт:

# определение подпрограммы с 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); # обработать данные

}

В других случаях ссылки на подпрограммы предпочтительнее поместить в хэш, чтобы в каждом его элементе подпрограмма ассоциировалась с нужным поисковым ключом. Как в этом примере:

my %refs2subs = ('SUM' => $ref2sum, 'MAX' => $ref2max);

print $refs2subs{'SUM'}->(1..3), " \n";

В Perl переменные по умолчанию видимы в пределах всей программы (точнее, в пределах пакета, но об этом будет рассказано позднее). Практика доказала, что использование глобальных переменных противоречит принципу модульности, поскольку связывает части программы зависимостями от глобальных данных. Поэтому во всех языках программирования предусмотрены средства ограничения видимости переменных. Как уже упоминалось в лекции 2, в Perl это делается с помощью объявления переменных. Чтобы ограничить видимость переменных рамками блока или подпрограммы, нужно объявить для них лексическую область видимости с помощью функции my, как это уже делалось в приводимых ранее примерах. Когда при помощи my объявляется несколько переменных, то все они должны заключаться в круглые скобки, как показано ниже:

my ($var1, $var2, $var3) = (1, 2, 3); # правильно

# запись my ($var1=1, $var2=2, $var3=3) ошибочна

my $var4 = 4, $var5 = 5; # $var5 - глобальная, а не my

Чтобы проследить, как изменяются значения переменных, объявленных в главной программе и подпрограммах, внимательно прочитайте следующий пример (скучный, но полезный для понимания):

use strict;

my $var = 'm'; # лексическая $var в main

Поделиться с друзьями: