Опубликован: 17.08.2006 | Доступ: свободный | Студентов: 5372 / 697 | Оценка: 4.49 / 3.94 | Длительность: 20:58:00
ISBN: 978-5-9556-0078-9
Лекция 12:

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

Возврат значений

В Perl все подпрограммы всегда возвращают значения. Если не указано ничего иного, возвращаемым значением будет значение последнего вычисленного в подпрограмме выражения. В следующем примере функция dice() возвращает список из двух случайных чисел от 1 до 6, имитируя бросок игральных костей:

sub dice { # бросаем игральные кости: 
   (int(rand 6)+1, int(rand 6)+1); # два случайных числа
}

Также в Perl есть встроенная функция возврата из подпрограммы return, которая завершает выполнение подпрограммы и возвращает значение указанного выражения. Так делается в пользовательской функции приветствия:

sub greeting { # приветствие в зависимости от времени суток
   my $hours = (localtime)[2]; # текущие часы 
   if ($hours >= 4 and $hours < 12) {
      return 'Доброе утро';
   } elsif ($hours >= 12 and $hours < 18) {
      return 'Добрый день';
   } elsif ($hours >= 18 and $hours < 22) {
      return 'Добрый вечер';
   } else {
      return 'Доброй ночи';
   }
}
print greeting(), '!';

Если выражение не указано, возвращается пустой список в списочном контексте и неопределенное значение undef - в контексте скалярном. В следующем примере функция проверки размера файла get_file_size() возвращает неопределенное значение как сигнал об отсутствии файла.

sub get_file_size { # узнать размер файла 
   return -s $file  # вернуть размер, в т.ч. 0,
      if -e $file;  # если файл существует
   return; # файла нет, вернуть undef 
}

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

Помня о том, что списки в Perl - одномерные, становится понятным, что подпрограмма в Perl может возвращать только один список. Например, если в ней записано return (@array1, @array2), будет возвращен объединенный список из элементов @array1 и @array2. Поэтому при необходимости вернуть несколько списочных объектов возвращаются ссылки на них, например: return (\@array1, \@array2).

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

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

sub cube { # вычислить куб числа
   return $_[0] * $_[0] * $_[0]; # умножить аргумент
}
print cube(2); # будет напечатано 8

Количество переданных аргументов можно выяснить, запросив число элементов массива @_. Для обработки списка аргументов переменной длины часто используется встроенная функция shift(), которая извлекает из массива параметров очередное значение, переданное подпрограмме:

print2files($message, $file1, $file2, $file3);
sub print2files { # вывести текст в несколько файлов
   my $text = shift; # 1-й параметр - текст
   while (@_) {
      my $file = shift; # очередное имя файла
      open my $fh, ">>$file" or die;
      print $fh $text;
      close $fh or die;
   }
}

Если переданные аргументы заданы переменными, то массив параметров @_ совмещается с переданными аргументами. Это означает, что изменение элементов массива приведет к изменению значений соответствующих переменных в вызывающей программе. Это можно проиллюстрировать следующим (несколько искусственным) примером:

sub sum2 { # вычислить сумму 2-х чисел
   $_[0] = $_[1] + $_[2]; # поместить сумму в 1-й аргумент
   return;
}
my $a = 1, $b = 2, $sum = 0;
sum2($sum, $a, $b);
print "$a+$b=$sum"; # будет напечатано: 1+2=3

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

sub get_file { # считать данные из файла
   my ($path, $file) = @_; # присвоить аргументы в переменные
   return unless -e "$path/$file"; # авария: файла нет
   open my $fh, '<', "$path/$file" or return;
   my @lines = <$fh>; # прочитать все строки файла в массив
   close $fh or return;
   return @lines; # вернуть массив строк файла
}
my @data = get_file('/tmp', 'log.txt');

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

По той же причине, по которой подпрограмма не может возвращать несколько списков, она не может получать несколько отдельных списков в виде аргументов. Например, если подпрограмма вызвана так: subr1(@array1, @array2), то ей будет передан объединенный список из элементов двух массивов @array1 и @array2. Поэтому если необходимо передать несколько списочных объектов, то передаются ссылки на них, например: subr1(\@array1, \@array2).

Сергей Крупко
Сергей Крупко

Добрый день.

Я сейчас прохожу курс  повышения квалификации  - "Профессиональное веб-программирование". Мне нужно получить диплом по этому курсу. Я так полагаю нужно его оплатить чтобы получить диплом о повышении квалификации. Как мне оплатить этот курс?

 

Галина Башкирова
Галина Башкирова

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

Системный администратор информационно-коммуникационных» систем.
Мне нужно самой найти тему? или делать по высланным темам