HTML page

Глава 10 Подпрограммы

Подпрограммы

Введение

Практика вставки/копирования кода довольно опасна, поэтому в больших программах многократно используемые фрагменты кода часто оформляются в виде подпрограмм. Для нас термины "подпрограмма" (subroutine) и "функция" (function) будут эквивалентными, поскольку в Perl они различаются ничуть не больше, чем в С. Даже объектно-ориентированные методы представляют собой обычные подпрограммы со специальным синтаксисом вызова, описанным в главе 13 "Классы, объекты и связи". Подпрограмма объявляется с помощью ключевого слова sub. Пример определения простой подпрограммы выглядит так:
sub hello {
$greeted++; # Глобальная переменная
print "hi there\n!";
}

Типичный способ вызова этой подпрограммы выглядит следующим образом:
hello(); # Подпрограмма hello вызывается без аргументов/параметров

Перед выполнением программы Perl компилирует ее, поэтому место объявления подпрограммы не имеет значения. Определения не обязаны находиться в одном файле с основной программой. Они могут быть взяты из других файлов с помощью операторов do, require или use (см. главу 12 "Пакеты, библиотеки и модули"), создаваться "на месте" с помощью ключевого слова eval или механизма AUTOLOAD или генерироваться посредством замыканий, используемых в шаблонах функций. Если вы знакомы с другими языками программирования, некоторые особенности функций Perl могут показаться странными. В большинстве рецептов этой главы показано, как применять эти особенности в свою пользу. o Функции Perl не имеют формальных, именованных параметров, но это не всегда плохо (см. рецепты 10.1 и 10.7). o Все переменные являются глобальными, если обратное не следует из объявления. Дополнительная информация приведена в рецептах 10.1 и 10.7. o Передача или возвращение нескольких массивов или хэшей обычно приводит к потере ими "индивидуальности". О том, как избежать этого, рассказано в рецептах 10.5, 10.8, 10.9 и 10.11. o Функция может узнать свой контекст вызова (списковый или скалярный), количество аргументов при вызове и даже имя функции, из которой она была вызвана. О том, как это сделать, рассказано в рецептах 10.4 и 10.6. o Используемое в Perl значение undef может использоваться в качестве признака ошибки, поскольку ни одна допустимая строка или число никогда не принимает это значение. В рецепте 10.10 описаны некоторые неочевидные трудности, связанные с undef, которых следует избегать, а в рецепте 10.12 показано, как обрабатываются другие катастрофические случаи. o В Perl функции обладают рядом интересных возможностей, редко встречи ющихся в других языках (например, анонимные функции, создание функ ций "на месте" и их косвенный вызов через указатель на функцию). Эти мистические темы рассматриваются в рецептах 10.14 и 10.16. При вызове вида $х = &func; функция не получает аргументов, по зато может напрямую обращаться к массиву @_ вызывающей стороны! Если убрать ампер-санд и воспользоваться формой func() или func, создается новый, пустой экземпляр массива @_.

10.1. Доступ к аргументам подпрограммы

Проблема

В своей функции вы хотите использовать аргументы, переданные вызывающей стороной.

Решение

Все значения, переданные 4)ункции в качестве аргументов, хранятся в специальном массиве @_. Следовательно, первый аргумент хранится в элементе $_[0], второй - в $_[1] и т. д. Общее число аргументов равно scalar(@_). Например:
sub hypotenuse {
return sqrt( ($_[0] ** 2) + ($_[1J ** 2) );
}
$diag = hypotenuse(3,4); # $diag = 5

В начале подпрограммы аргументы почти всегда копируются в именованные закрытые переменные для удобства и повышения надежности:
sub hypotenuse {
my ($side1, $side2) = @_;
return sqrt( ($side1 ** 2) + ($slde1 ** 2) );
}

Комментарий

Говорят, в программировании есть всего три удобных числа: ноль, единица и "сколько угодно". Механизм работы с подпрограммами Perl разрабатывался для упрощения написания функций со сколь угодно большим (или малым) числом параметров и возвращаемых значений. Все входные параметры хранятся в виде отдельных скалярных значений в специальном массиве @_, который автоматически становится локальным для каждой функции (см. рецепт 10.13). Для возвращения значений из подпрограмм следует использовать команду return с аргументом. Если она отсутствует, возвращаемое значение представляет собой результат по следнего вычисленного выражения. Приведем несколько примеров вызова функции hypotenuse, определенной в решении:
print hypotenuse(3, 4), "\n"; # Выводит 5
@а = (3, 4);
print hypotenuse(@a), "\n"; # Выводит 5

Если взглянуть на аргументы, использованные во втором вызове hypotenuse, может показаться, что мы передали лишь один аргумент - массив @а. Но это не так - элементы @а копируются в массив @_ по отдельности. Аналогично, при вызове функции с аргументами (@а, @Ь) мы передаем ей все аргументы из обоих массивов. При этом используется тот же принцип, что и при сглаживании списков:
@both = (@men, @women);

Скалярные величины в ^представляют собой неявные синонимы для передаваемых значений, а не их копии. Таким образом, модификация элементов @_ в подпрограмме приведет к изменению значений на вызывающей стороне. Это тяжкое наследие пришло из тех времен, когда в Perl еще не было нормальных ссылок. Итак, функцию можно записать так, чтобы она не изменяла свои аргументы -для этого следует скопировать их в закрытые переменные:
@nums = (1,4, 3,5, 6.7);
@ints = int_all(@nums); # @nums не изменяется
sub int_all {
my @retlist = @_; # Сделать копию для return
for my $n (@retlist) { $n = int($n) }
return @retlist;
}


В начале подпрограммы аргументы почти всегда копируются в именованные закрытые переменные для удобства и повышения надежности:
sub hypotenuse {
my ($side1, $side2) = @_;
return sqrt( ($side1 ** 2) + ($side1 ** 2) );
}

Комментарий

Говорят, в программировании есть всего три удобных числа: ноль, единица и "сколько угодно". Механизм работы с подпрограммами Perl разрабатывался для упрощения написания функций со сколь угодно большим (или малым) числом параметров и возвращаемых значений. Все входные параметры хранятся в виде отдельных скалярных значений в специальном массиве @_, который автоматически становится локальным для каждой функции (см. рецепт 10.13). Для возвращения значений из подпрограмм следует использовать команду return с аргументом. Если она отсутствует, возвращаемое значение представляет собой результат последнего вычисленного выражения. Приведем несколько примеров вызова функции hypotenuse, определенной в решении:
print hypotenuse(3, 4), "\n"; # Выводит 5
@а = (3, 4);
print hypotenuse(@a), "\n"; # Выводит 5
Если взглянуть на аргументы, использованные во втором вызове hypotenuse, может показаться, что мы передали лишь один аргумент - массив @а. Но это не так - элементы @а копируются в массив @_ по отдельности. Аналогично, при вызове функции с аргументами (@а, @Ь) мы передаем ей все аргументы из обоих массивов. При этом используется тот же принцип, что и при сглаживании списков:
@both = (@men, @women);

Скалярные величины в @_ представляют собой неявные синонимы для передаваемых значений, а не их копии. Таким образом, модификация элементов @>_ в подпрограмме приведет к изменению значений на вызывающей стороне. Это тяжкое наследие пришло из тех времен, когда в Perl еще не было нормальных ссылок. Итак, функцию можно записать так, чтобы она не изменяла свои аргументы -для этого следует скопировать их в закрытые переменные:
@nums = (1.4, 3.5, 6.7);
@ints = int_all(@nums); # @nums не изменяется
sub int_all {
vmy @retlist = @_; # Сделать копию для return
for my $n (@retlist) { $n = int($n) }
return @retlist;

Впрочем, функция также может изменять значения, переменных вызывающей стороны:
@nums = (1.4, 3.5. 6.7);
trunc_em(@nums);
@nums = (1,3,6)
sub trunc_em {
for (@_) { $_ = int($_) } # Округлить каждый аргумент
}

Таким функциям не следует передавать константы - например, trunc_em(l .4, 3.5, 6.7). Если попытаться это сделать, будет возбуждено исключение Modification of a read-only value attempted at... ("Попытка модифицировать величину, доступную только для чтения"). Встроенные функции спориспотр работают именно так - они модифицируют переменные вызывающей стороны и возвращают удаленный символ(-ы). Многие привыкают к тому, что функции возвращают измененные значения, и часто пишут в программах следующее:
$line = chomp(<>); # НЕВЕРНО

пока не поймут, что происходит в действительности. Учитывая широкие возможности для ошибок, перед модификацией @_ в подпрограмме стоит дважды подумать.

> Смотри также ------------------------------
perlsub(1).

10.2. Создание закрытых переменных в функциях

Проблема

В подпрограмме потребовалось создать временную переменную. Использование глобальных переменных нежелательно, поскольку другие подпрограммы-могут получить к ним доступ.

Решение

Воспользуйтесь ключевым словом ту для объявления переменной, ограниченной некоторой областью программы:
sub somefunc {
my $variable; # Переменная $variable невидима
# за пределами somefunc()
my ($another, @an_array, %a_hash); # Объявляем несколько
# переменных сразу
#...
}

Комментарий

Оператор my ограничивает использование переменной и обращение к ней определенным участком программы. За пределами этого участка переменная недоступна. Такой участок называется областью действия (scope). Переменные, объявленные с ключевым словом ту, обладают лексической областью действия - это означает, что они существуют лишь в границах некоторого фрагмента исходного текста. Например, областью действия переменной $variable из решения является функция somefunc, в которой она была определена. Переменная создается при вызове somefunc и уничтожается при ее завершении. Переменная доступна внутри функции, но не за ее пределами. Лексическая область действия обычно представляет собой программный блок, заключенный в фигурные скобки, - например, определение тела подпрограммы somefunc или границы команд if, while, for, foreach и eval. Лексическая область действия также может представлять собой весь файл или строку, переданную eval. Поскольку лексическая область действия обычно является блоком, иногда мы говорим, что лексические переменные (переменные с лексической областью действия) видны только в своем блоке - имеется в виду, что они видны только в границах своей области действия. Простите нам эту неточность, иначе слова "область действия" и "подпрограмма" заняли бы половину этой книги. Поскольку фрагменты программы, в которых видна переменная ту, определяются во время компиляции и не изменяются позднее, лексическая область действия иногда не совсем точно называется "статической областью действия". Ее противоположностью является динамическая область действия, рассмотренная в рецепте 10.13. Объявление ту может сочетаться с присваиванием. При определении сразу нескольких переменных используются круглые скобки:
mу ($nаmе, $аgе) = @argv;
mу $start = fetch_time();
Эти лексические переменные ведут себя как обычные локальные переменные., Вложенный блок видит лексические переменные, объявленные в родительских по отношению к нему блоках, но не в других, не связанных с ними блоках:
my ($a, $b) = @pair;
mу $с = fetch_time();
sub check_x {
mу $х = $_[0];
mу $у = "whatever";
run_check();
if ($condition) { print "got $x\n";
} }


В приведенном выше фрагменте блок if внутри функции может обращаться i закрытой переменной $х. Однако в функции run_check, вызванной из этой облас' ти, переменные $х и $у недоступны, потому что она предположительно определяется в другой области действия. Однако check_x может обращаться к $а, $Ь и $с из внешней области, поскольку определяется в одной области действия с этими переменными. Именованные подпрограммы не следует объявлять внутри объявлений других именованных подпрограмм. Такие подпрограммы, в отличие от полноценных замыканий, не обеспечивают правильной привязки лексических переменных. В рецепте 10.16 показано, как справиться с этим ограничением.При выходе лексической переменной за пределы области действия занимаемая ей память освобождается, если на нее не существует ссылок, как для массива @arguments в следующем фрагменте:
sub save_array {
my (@arguments = @_;
push (@Global_Array, \@arguments);
}

Система сборки мусора Perl знает о том, что память следует освобождать лишь для неиспользуемых объектов. Это и позволяет избежать утечки памяти при возвращении ссылки на закрытую переменную.

> Смотри также -------------------------------
Раздел "Private Variables via my()" perlsub(1).

10.3. Создание устойчивых закрытых переменных

Проблема

Вы хотите, чтобы переменная сохраняла значение между вызовами подпрограммы, но не была доступна за ее пределами. Например, функция может запоминать, сколько раз она была вызвана.

Решение

"Заверните" функцию во внешний блок и объявите переменные ту в области действия этого блока, а не в самой функции:
{
my $variable;
sub mysub {
# ... обращение к $variable
} }

Если переменные требуют инициализации, снабдите блок ключевым словом BEGIN, чтобы значение переменных заведомо задавалось перед началом работы основной программы:
BEGIN {
my $variable =1; # Начальное значение
sub othersub { #... обращение к $variable
} }

Комментарий

В отличие от локальных переменных в языках С и C++, лексические переменные Perl не всегда уничтожаются при выходе из области действия. Если нечто, продолжающее существовать, все еще помнит о лексической переменной, память не освобождается. В нашем примере mysub использует переменную $variable, поэтому Perl не освобождает память переменной при завершении блока, вмещающего определение mysub. Счетчик вызовов реализуется следующим образом:
{
my $counter;
sub next_counter { return ++$counter }
}
.
При каждом вызове next_counter функция увеличивает и возвращает переменную $counter. При первом вызове переменная $counter имеет неопределенное значение, поэтому для оператора ++ она интерпретируется как 0. Переменная входит не в область действия next_counter, а в окружающий ее блок. Никакой внешний код не сможет изменить $counter без вызова next_counter. Для расширения области действия обычно следует использовать ключевое слово BEGIN. В противном случае возможен вызов функции до инициализации переменной.
BEGIN {
my @counter = 42;
sub riext_couhter {return ++$counter }
sub prev_counter { return --$counter } }
.
Таким образом, в Perl создается аналог статических переменных языка С. В действительности он даже лучше - переменная не ограничивается одной функцией, и обе функции могут совместно использовать свою закрытую переменную.

> Смотри также ------------------------------
Раздел "Private Variables via my()" perlsub(1); раздел "Package Constructors and ; Destructors" perlmod(1); рецепт 11.4.

10.4. Определение имени текущей функции

Проблема

Требуется определить имя функции, работающей в настоящий момент. Оно пригодится для сообщений об ошибках, которые не изменяются при копировании/ вставке исходного текста подпрограммы.

Решение

Воспользуйтесь функцией caller:
$this_function = (caller(0))[3];

Комментарий

Программа всегда может определить текущей номер строки с помощью специальной метапеременной __LINE__ Текущий файл определяется с помощью мета-переменной __FILE__, а текущий пакет-__PACKAGE__ Однако не существует метапеременной для определения имени .текущей подпрограммы, не говоря уже об имени той, из которой она была вызвана. Встроенная функция caller справляется со всеми затруднениями. В скалярном контексте она возвращает имя пакета вызывающей функции, а в списковом контексте возвращается список с разнообразными сведениями. Функции также можно передать число, определяющее уровень вложенности получаемой информации: 0 - ваша функция, 1 - функция, из которой она была вызвана, и т. д. Полный синтаксис выглядит следующим образом ($i - количество уровней вложенности):
($package, $filename, $Цпе, $subr, $has_args, $wantarray )= caller($i);
# 0 1 2 3 4 5 ;
Возвращаемые значения имеют следующий смысл:
$package Пакет, в котором был откомпилирован код:
$filename

Имя файла, в котором был откомпилирован код. Значение -е возвращается при запуске из командной строки, а значение - (дефис) - при чтении сценария из STDIN. $line Номер строки, из которой был вызван данный кадр стека:
$subr
Имя функции данного кадра, включающее ее пакет. Замыкания возвращают имена вида main:: _ANON__, вызов по ним невозможен. Для eval возвращается " (eval)". $has_args Признак наличия аргументов при вызове функции: $wantarray Значение, возвращаемое функцией wanfarray для данного кадра.стека. Равно либо true, либо false, либо undef. Сообщает, что функция была вызвана в списковом, скалярном или неопределенном контексте. Вместо непосредственного; вызова caller, продемонстрированного в решении, можно написать вспомогательные функции:
$me = whoami();
$him = whowasi();
sub whoami { (caller(1))[3] }
sub whowasi { (caller(2))[3] }

Аргументы 1 и 2 используются для функций первого и второго уровня вложенности, поскольку вызов whoami или whowasi будет иметь нулевой уровень.

> Смотри также -----------------------------
Описание функций wantarray и caller в perlfunc(i); рецепт 10.6.

10.5. Передача массивов и хэшей по ссылке

Проблема

Требуется передать функции несколько массивов или хэшей и сохранить их как отдельные сущности. Например, вы хотите выделить в подпрограмму алгоритм поиска элементов одного массива, отсутствующих в другом массиве, из рецепта 4.7. При вызове подпрограмма должна Получать два массива, которые не должны смешиваться.
array_diff( \@аrrау1, \@аrrау2 );

Комментарий

Операции со ссылками рассматриваются в главе 11 "Ссылки и записи". Ниже показана подпрограмма, получающая ссылки на массивы, и вызов, в котором эти ссылки генерируются:
@а = (1, 2);
@b = (5, 8);
@с = add_vecpair( \@a, \@b );
print "@c\n";
6 10
sub add_vecpair {
my ($x, $y) = @_ my @result; # Предполагается, что оба вектора
# имеют одинаковую длину
# Скопировать ссылки на массивы
for (my $i=0; $i < @$x; $i++)
{ $result[$i] = $x->-[$i] + $y->[$i];
}
return @result;

Функция обладает одним потенциальным недостатком: она не проверяет, что ей были переданы в точности два аргумента, являющиеся ссылками на массивы. Проверку можно организовать следующим образом:
unless (@_ == 2 && ref($x) eq -array' && ref($y) eq -array") {
die "usage: add.vecpair ARRAYREF1 ARRAYREF2";
}

Если вы собираетесь ограничиться вызовом die в случае ошибки (см. рецепт 10.12), проверка обычно пропускается, поскольку при попытке разыменования недопустимой ссылки все равно возникает исключение.

> Смотри также-------------------
Раздел "Pass by Reference" perlsub(1) раздел "Prototypes" perlsub(i); рецепт 10.11; глава 11 глава 11. 10.6. Определение контекста вызова Проблема Требуется узнать, была ли ваша функция вызвана в скалярном или списковом контексте. Это позволяет решать разные задачи в разных контекстах, как это делается в большинстве встроенных функций Perl. Решение Воспользуйтесь функцией wantarray(), которая возвращает три разных значения в зависимости от контекста вызова текущей функции:
if (wantarray()) {
# Списковый контекст
}
elsif (defined wantarray()) {
# Скалярный контекст
}
else { # Неопределенный контекст
}

Комментарий

Многие встроенные функции, вызванные в скалярном контексте, работают совсем не так, как в списковом контексте. Пользовательская функция может узнать контекст своего вызова с помощью значения, возвращаемого встроенной функцией wantarray. Для спискового контекста wantarray возвращает true. Если возвращается ложное, но определенное значение, функция используется в скалярном контексте. Если возвращается undef, от функции вообще не требуется возвращаемого значения.
if (wantarray()) {
print "In list context\n";
return @many_things;
} etsif (defined wanfarrayO) {
print "In scalar context\n";
return $one_thing;
} else {
print "In void context\n";
return; # Ничего
} mysub();# Неопределенный контекст $a = mysub(); # Скалярный контекст if (mysubo) { } # Скалярный контекст @a = mysub(); # Списковый контекст print mysub(); # Списковый контекст


Смотри также
Описание функций return и wantarray в perlfunc(1).

10.7. Передача именованных параметров

Проблема

Требуется упростить вызов функции с несколькими параметрами, чтобы программист помнил смысл параметров, а не порядок их следования.

Решение

Укажите имена параметров при вызове:
thefunc(INCREMENT => "20s", START => "+5m", FINISH => "+30m");
thefunc(START => "+5m", FINISH => "+30m");
thefunc(FINISH => "+30m");
thefunc(START => "+5m", INCREMENT => "15s");

Затем в подпрограмме создайте хэш, содержащий значения по умолчанию и массив пар:
sub thefunc { my %args = ( increment finish start=> '10s', => 0, => 0,
# Список пар аргументов
if ($args{INCREMENT} =~ /m$/ ) {...}

Комментарий

Функции, аргументы которых должны следовать в определенном порядке, удобны для небольших списков аргументов. Но с ростом количества аргументов становится труднее делать некоторые из них необязательными или присваивать им значения по умолчанию. Пропускать можно только аргументы, находящиеся в конце списка, и никогда - в начале. Более гибкое решение - передача пар значений. Первый элемент пары определяет имя аргумента, а второй - значение. Программа автоматически документируется, поскольку смысл параметра можно понять, не читая полное определение функции. Более того, программистам, использующим такую функцию, не придется запоминать порядок аргументов, и они смогут пропускать любые аргументы. Решение построено на объявлении в функции закрытого хэша, хранящего значения параметров по умолчанию. В конец хэша заносится массив текущих аргументов, @_ - значения по умолчанию заменяются фактическими значениями аргументов.

[> Смотри также ------------------------------
Глава 4 "Массивы".

10.8. Пропуск некоторых возвращаемых значений

Проблема

Имеется функция, которая возвращает много значений, однако вас интересуют лишь некоторые из них. Классический пример - функция stat; как правило, требуется лишь одно значение из длинного возвращаемого списка (например, режим доступа). Решение Присвойте результат вызова списку, некоторые позиции которого равны undef:
($а, undef, $с) = func();

Либо создайте срез списка возвращаемых значений и отберите лишь то, что вас интересует:
($а, ,$с) = (func())[0.2];

Комментарий

Применять фиктивные временные переменные слишком расточительно:
($dev,$ino,$DUMMY,$DUMMY,$uid) = stat($filename);
Чтобы отбросить ненужное значение, достаточно заменить фиктивные переменные на undef:
($dev,$ino,undef,undef,$uid) = stat($filename);

Также можно создать срез и включить в него лишь интересующие вас значения:
($dev,$lno,$uid,$gid) = (stat($filename))[0,1,4,5];

Если вы хотите перевести результат вызова функции в списковый контекст и отбросить все возвращаемые значения (вызывая его ради побочных эффектов), начиная с версии 5.004, можно присвоить его пустому списку:
() = some_function();


> Смотри также -------------------------------
Описание срезов в perlsub(1); рецепт 3.1.

10.9. Возврат нескольких массивов или хэшей

Проблема

Необходимо, чтобы функция возвратила несколько массивов или хэшей, однако возвращаемые значения сглаживаются в один длинный список скалярных величин.

Решение

Возвращайте ссылки на хэши или массивы:
($array_ref, $hash_ref) = somefunc();
sub somefunc { my @array;
my %hash;
return ( \@array, \%hash );
}

Комментарий

Как говорилось выше, все аргументы функции сливаются в общий список скалярных величин. То же самое происходит и с возвращаемыми значениями. Функция, возвращающая отдельные массивы или хэши, должна возвращать их по ссылке, и вызывающая сторона должна быть готова к получению ссылок. Например, возвращение трех отдельных хэшей может выглядеть так:
sub fn {
return (\%a, \%b, \%c); # или
return \(%a, %Ь, %с); # то же самое
}

Вызывающая сторона должна помнить о том, что функция возвращает список ссылок на хэши. Она не может просто присвоить его списку из трех хэшей.
(%h0, %h1, %h2) = fn(); # НЕВЕРНО!
@array_of.hashes = fn(); # например:
$array"of_hashes[2]->{"keystring"}
($r0, $r1, $r2) = fn(); # например:
$r2->{"keystring"}


> Смотри также ------------------------------
Общие сведения о ссылках в главе 11; рецепт 10.5.

10.10. Возвращение признака неудачного вызов

Проблема

Функция должна возвращать значение, свидетельствующее о неудачной попытке вызова.

Решение

Воспользуйтесь командой return без аргументов, которая в скалярном контексте возвращает undef, а в списковом - пустой список ().

Комментарий


return без аргументов означает следующее:
sub empty_retval {
return ( wantarray ? () : undef );
}

Ограничиться простым return undef нельзя, поскольку в списковом контексте вы получите список из одного элемента: undef. Если функция вызывается в виде:
if (@а = yourfunc()) { ... }

то признак ошибки будет равен true, поскольку @а присваивается список (undef), интерпретируемый в скалярном контексте. Результат будет равен 1 (количество элементов в @а), то есть истинному значению. Контекст вызова можно опреде-лить.с помощью функции wantarray, однако return без аргументов обеспечивает более наглядное и изящное решение, которое работает в любых ситуациях:
unless ($а = sfunc()) { die "afuno failed" }
unless (@a = afunc()) { die", "afunc failed",}
unless (%a = hfunc()) { die "hfunc failed" }

Некоторые встроенные функции Perl иногда возвращают довольно странные значения. Например, fcnti и iocti в некоторых ситуациях возвращают строку
"0 but true'' (для удобства эта волшебная строка была изъята из бесчисленных предупреждений об ошибках преобразования флага -w). Появляется возможность использовать конструкции следующего вида:
ioctl(....) or die "can't iocti: $!";

В этом случае программе не нужно отличать определенный ноль от неопределенного значения, как пришлось бы делат^ для функций read или glob. В числовой интерпретации "Q but true" является нулем. Необходимость в возвращении подобных значений возникает довольно редко. Более распространенный (и эффектный) способ сообщить о неудаче при вызове функции заключается в инициировании исключения (см. рецепт 10.12).

> Смотри также ------------------------------
Описание функций wantarray и return в perlfunc(1); рецепт 10.12.


copyright 2000 Soft group