Поиск

Создание и вызов подпрограмм

Для создания пользовательских подпрограмм в Perl используется следующий синтаксис:

Имена подпрограмм подчиняются тем же соглашениям об именах, что и имена скаляров, массивов и хэшей. Эти соглашения рассматривались на 2-м занятии, "Строительные блоки Perl: числа и строки". Имена подпрограмм могут совпадать с именами переменных.

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

При вызове подпрограммы запускается ее код и возвращаемое значение передается в то место, из которого была вызвана подпрограмма. Например, данная короткая подпрограмма используется для диалога с пользователем:

Для инициирования подпрограммы, или, как еще говорят, ее вызова можно использовать подобные строки:

Второй синтаксис (без &) можно использовать, если подпрограмма была ранее определена в коде, а синтаксис &yesno( )допустим в любом месте кода. В этой книге используются вызовы подпрограмм без S, хотя обе формы синтаксиса могут иметь место.

При вызове подпрограммы Perl запоминает место, в котором произошел вызов, выполняет код подпрограммы и затем возвращается в основную программу к месту вызова:

Подпрограммы Perl могут быть вызваны в любом месте основной программы и даже из других подпрограмм:

Возврат значений из подпрограмм

Подпрограмма служит не только для удобной группировки кода с возможностью его вызова по имени. Подпрограмма, как и функции, операторы и выражения Perl, имеет значение. Оно называется возвращаемым значением. Возвращаемое значение подпрограммы — значение последнего вычисленного в подпрограмме выражения или же значение, явно возвращаемое оператором return.

Значение подпрограммы вычисляется после вызова подпрограммы и затем используется в том месте, из которого подпрограмма была вызвана. Вот пример:

Здесь Perl при вычислении выражения 8*two__by_four() вызывает подпрограмму two_by_four(), которая возвращает значение 8. Затем вычисляется выражение 8*8 и в итоге выводится 64.

Значения подпрограмм также могут явно возвращаться оператором return. Этот оператор используется для досрочного выхода из кода подпрограммы и явного указания возвращаемого значения. В приведенном ниже примере используются оба способа выхода:

Подпрограммы могут возвращать не только скаляры, а и массивы или хэши:

Аргументы

У всех предыдущих примеров общим было то, что данные, с которыми они работали, были или литералами (2*4), или переменными главной программы ($х в x_greaterthanlO0). Эти ограничения создают проблему переносимости кода подпрограмм. Для преодоления этих ограничений нужно уметь вызвать функцию и сказать ей: "Возьми эти данные и выполни с ними некоторые действия", а затем сказать ей: "Возьми другие данные и выполни с ними некоторые действия". Поведение функции должно изменяться в зависимости от передаваемых ей данных.

Значения, передаваемые функции и изменяющие ее поведение, называются аргументами (мы уже неоднократно использовали в книге этот термин). Вы уже знаете, что встроенным функциям Perl (grep, sort, reverse, print и др.) можно передавать аргументы. То же относится и к вашим подпрограммам. Для передачи функции аргументов можно использовать любой синтаксис:

Вторая форма — без скобок — может быть использована, только если интерпретатор Perl уже встречал определение этой функции.

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

Для доступа к индивидуальным аргументам можно использовать индексы массива @_, как и в случае любого другого массива. Однако следует помнить, что конструкция $_[0] не имеет никакого отношения к скалярной переменной $_.

Использование в качестве имен переменных конструкции типа $_[3] — не очень прозрачный стиль программирования. Функции, в которых много переменных, как правило, начинаются с переименования этих переменных ~ после этого становится понятно, для чего они предназначены. Посмотрите, что имеется в виду:

Здесь массив @_ копируется в список ($hits, $at_bats). Первый элемент массива @_ — @_[0] — становится переменной ?hits, а второй — переменной $at_bats. Имена переменных использованы лишь для читабельности.

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

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

В этой подпрограмме обращение к массиву @items осуществляется посредством переменной @_:

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

Массивы @first и @second передаются при вызове подпрограммы в одном списке @_. Внутри этого большого плоского списка невозможно определить конец первого массива и начало второго. В подпрограмме оператор присваивания (@а, @b)=@_ приводит к тому, что все элементы массива @ становятся элементами массива @а, а массив @b так и останется пустым списком. Чтобы вспомнить, почему это происходит, обратитесь к материалу 4-го занятия, "Укладка строительных блоков: списки и массивы".

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

Если нужно передать в подпрограмму несколько массивов или хэшей, а затем отделить их друг от друга, используйте указатели. О том, как передавать в подпрограммы указатели, речь пойдет на 13-м занятии, "Структуры и ссылки".