Создание серверных приложений на языке PERL

         

Управляющие структуры


Блоки операторов

Блок операторов — это последовательность операторов, заключенная в парные фигурные скобки. Блок операторов выглядит следующим образом:

(

первыи_оператор;

второй_оператор;

третий_оператор;

последний_оператор;

>

Perl выполняет операторы по очереди, начиная с первого и кончая последним. (Позднее вы узнаете о том, как можно изменять порядок выполнения в блоке, но пока достаточно и этого.)

Синтаксически блок операторов принимается вместо любого одиночного оператора, но обратное не верно.

Завершающая точка с запятой, стоящая за последним оператором, не обязательна. Таким образом, вы можете разговаривать на языке Perl с С-акцентом (точка с запятой присутствует) или с паскалевским акцентом (точка с запятой отсутствует). Чтобы облегчить последующее добавление операторов, мы обычно рекомендуем опускать точку с запятой лишь в том случае, если блок занимает целую строку. Сравните примеры этих стилей в следующих двух блоках if:

if ($ready) ( $hungry++ } if ($tired) (

$sleepy = ($hungry + 1) * 2;

}

Оператор if/unless



Следующей по сложности управляющей структурой является оператор if. Эта конструкция состоит из управляющего выражения (проверяемого на истинность) и блока. В ней также может быть часть, начинающаяся оператором else, за которой следует еще один блок операторов. Другими словами, все это выглядит так:

if (выражение) (

оператор_1

оператор_2

оператор_3 }

else {

оператор_1

оператор_2

оператор_3 }

(Если вы любите программировать на С и Java, то для вас должна быть вполне очевидной обязательность фигурных скобок. Они устраняют необходимость в применении правила "путающего зависшего else".)

Во время выполнения Perl-программы вычисляется управляющее выражение. Если оно истинно, то выполняется первый блок операторов в приведенном выше примере. Если выражение ложно, то выполняется второй блок.

Что же такое "истина" и "ложь"? В Perl эти правила несколько странноваты, но, тем не менее, дают ожидаемые результаты. Управляющее выражение вычисляется как строковая величина в скалярном контексте (если это уже строка, ничего не изменяется, а если это число, то оно преобразуется в строку*). Если данная строка либо пуста (т.е. имеет нулевую длину), либо состоит из одного символа "О" (цифры нуль), то значение выражения — "ложь". Все остальное автоматически дает значение "истина". Почему же в Perl столь забавные правила? А потому, что это облегчает условный переход не только по нулю (в противоположность ненулевому числу), но и по пустой (в противоположность непустой) строке, причем без необходимости создания двух версий интерпретируемых значений "истина" и "ложь". Вот несколько примеров интерпретации этих значений.


О # преобразуется в "О", поэтому "ложь"

1-1 # дает в результате 0, затем преобразуется в "О", поэтому "ложь"

1 # преобразуется в "I", поэтому "истина"

"" # пустая строка, поэтому "ложь"

"1" # не "" или "О", поэтому "истина"

"00" # не "" или "О", поэтому "истина" (это странно, поэтому будьте настороже)

"0.000" # "истина" — будьте внимательны, по той же причине

undef # дает в результате "", поэтому "ложь"

* Внутренне все трактуется несколько иначе, но внешне все выполняется так, будто именно это и происходит.

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

print "how old are you? ";

$a = <STDIN>;

chomp($a) ;

if ($a < 18) (

print "So, you're not old enough to vote, eh?\n";

( else (

print "Old enough! Cool! So go vote! \n";

$voter++; # count the voters for later )

Блок else можно опустить, оставив только часть, касающуюся then:

print "how old are you? ";

$a - <STDIN>;

chomp($a) ;

if ($a < 18) (

print "So, you're not old enough to vote, eh?\n";

}

Иногда бывает удобно часть "then" опустить и оставить только else, потому что более естественно сказать "сделайте то, если это ложь", нежели "сделайте то, если это — не истина". В Perl этот вопрос решается с помощью оператора unless:

print "how old are you? ";

$a = <STDIN>;

chomp ($a) ;

unless ($a < 18) (

print "Old enough! Cool! So go vote!\n";

$voter++;

>

Заменить if на unless — это все равно что сказать "Если управляющее выражение ложно, сделать..." (Оператор unless может содержать блок else, как и оператор if.)

Если у вас больше двух возможных вариантов, введите в оператор if ветвь elsif, например:



if (выражение один) {

оператор_1_при_истине_ один;

оператор_2 _при_истине_один;

оператор_ 3_при_истине_ один ;

} elsif (выражение_два) {

оператор_1_при_истине_два

оператор_2_при_истине_два

олератор_3_при_истине_два } elsif (варажение_три) (

оператор_1_при_истине_три

оператор_2_при_истине_три

оператор _ 3_при_истине_ три

} else ( -

оператор__ 1_при_всеи_ложных;

оператор_2_при_в

сех_ложных/ оператор_3_при_всех_ложных;

}

Все управляющие выражения вычисляются по очереди. Если какое-либо выражение истинно, то выполняется соответствующая ветвь, а все остальные управляющие выражения и соответствующие блоки операторов пропускаются. Если все выражения ложны, то выполняется ветвь else (если таковая имеется). Присутствие блока else не обязательно, но он никогда не помешает. В программе может быть столько ветвей elsif, сколько вам необходимо.



Оператор while/until



Ни один язык программирования не был бы полным без какой-нибудь формы организации цикла* (повторяющегося выполнения блока операторов). Perl может организовать цикл с помощью оператора while:

while (выражение) {

оператор_1; '

оператор_2;

оператор_3;

}

Чтобы выполнить оператор while, Perl вычисляет управляющее выражение (в данном примере — выражение). Если полученное значение — "истина" (по принятым в Perl правилам установления истинности), то один раз вычисляется тело оператора while. Это повторяется до тех пор, пока управляющее выражение не станет ложным. Тогда Perl переходит к оператору, следующему после цикла while. Например:

print "how old are you? " ;

$a = <STDIN>;

chomp($a) ;

while ($a > 0) {

print "At one time, you were $a years old.\n";

$a—;

}

Иногда легче сказать "до тех пор, пока что-то не станет истинным", чем "пока не это — истина". Для этого случая у Perl тоже есть ответ. Требуемый эффект дает замена while на until:

until (выражение) { оператор_1;

оператор_2;

оператор_3;

} * Вот почему HTML — не язык программирования.



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

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



Оператор do {} while/until



Оператор while/until, который вы видели в предыдущем разделе, проверяет условие в начале каждого цикла, до входа в него. Если результат проверки условия — "ложь", цикл не будет выполнен вообще.

Иногда возникает необходимость проверять условие не в начале, а в конце цикла. Для этого в Perl есть оператор do {} while, который очень похож на обычный оператор while*, за исключением того, что он проверяет выражение только после однократного выполнения цикла.

do (

оператор_1;

опвратор_2;

оператор_3;

}

while выражение;

Perl выполняет операторы блока do. Дойдя до конца, он вычисляет выражение на предмет истинности. Если выражение ложно, цикл завершается. Если выражение истинно, весь блок выполняется еще раз, а затем выражение проверяется вновь.

Как и в обычном цикле while, условие проверки можно инвертировать, заменив do {} while на do {} until. Выражение все равно проверяется в конце цикла, но на обратное условие. В некоторых случаях, особенно сложных, такой способ записи условия представляется более естественным.

$stops = 0;

do (

$stops++;

print "Next stop? " ;

chomp($location = <STDIN>) ;

} until $stops > 5 I I $location eq 'home';

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





Оператор for



Еще одна конструкция Perl, предназначенная для организации цикла, — оператор for, который выглядит подозрительно похоже на оператор for языков С и Java и работает примерно так же. Вот он:

for ( начальное_выражение; проверочное_выражение ,• возобновляющее выражение ) (

оператор_1;

оператор_2;

оператор_3;

1

Если преобразовать этот оператор в те формы, которые мы рассмотрели раньше, то он станет таким:

начальное выражение;

while (проверочное выражение) {

оператор_1;

оператор_2;

оператор_3;

возобяовляющее_выраи:ение;

}

В любом случае сначала вычисляется начальное выражение. Это выражение, как правило, присваивает начальное значение переменной цикла, но никаких ограничений относительно того, что оно может содержать, не существует; оно даже может быть пустым (и ничего не делать). Затем вычисляется проверочное выражение. Если полученное значение истинно, выполняется тело цикла, а затем вычисляется возобновляющее выражение (как правило, используемое для инкрементирования переменной цикла — но не только для этого). Затем Perl повторно вычисляет проверочное выражение, повторяя необходимые действия.

Следующий фрагмент программы предназначен для вывода на экран чисел от 1 до 10, после каждого из которых следует пробел:

for ($i = 1; $i <- 10; $i++) ( print "$i ";

)

Сначала переменная $i устанавливается в 1. Затем эта переменная сравнивается с числом 10. Поскольку она меньше или равна 10, то выполняется тело цикла (один оператор print), а затем вычисляется возобновляющее выражение ($i++), в результате чего значение $i изменяется на 2. Поскольку эта переменная все еще меньше или равна 10, процесс повторяется до тех пор, пока в последней итерации значение 10 в $i не изменится на 11. Поскольку переменная $i уже не меньше и не равна 10, цикл завершается (при этом $i становится равным 11).



Оператор foreach



Еще одна циклическая конструкция — оператор foreach. Этот оператор получает список значений и присваивает их по очереди скалярной переменной, выполняя с каждым последующим присваиванием блок кода. Выглядит это так:



foreach

$i (@список) {

оператор_1;

оператор_2;

оператор_3;

}

В отличие от C-shell, в Perl исходное значение этой скалярной переменной при выходе из цикла автоматически восстанавливается; другими словами, эта скалярная переменная локальна для данного цикла.

Вот пример использования оператора foreach:

@а = (1,2,3,4,5);

foreach $b (reverse @a) { print $b;

1

Эта программа выводит на экран 54321. Отметим, что список, используемый в операторе foreach, может быть произвольным списочным литералом, а не просто переменной-массивом. (Это справедливо для всех конструкций Perl, которым требуется список.)

Имя скалярной переменной можно опустить. В этом случае Perl будет действовать так, как будто вы указали имя переменной $_. Вы увидите, что переменная $_ используется по умолчанию во многих операциях языка Perl, поэтому ее можно рассматривать как неявную временную переменную. (Все операции, в которых по умолчанию используется $_, могут использовать и обычную скалярную переменную.) Например, функция print выводит значение переменной $_, если другие значения не указаны, поэтому следующий пример дает такой же результат, как и предыдущий:

@а = (1,2,3,4,5);

foreach (reverse @a)

{

print ;

}

Видите, насколько использование неявной переменной $_ все упрощает? Когда вы познакомитесь с другими функциями и операциями, которые по умолчанию используют $_, то еще выше оцените полезность данной конструкции. Это один из тех случаев, когда короткая конструкция более понятна, чем длинная.

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

@а = (3,5,7,9) ;

foreach $one (@a) { $one *= 3;

> # @а теперь равно (9,15,21,27)



Обратите внимание на то, что изменение переменной $опе привело к изменению каждого элемента массива @а.



Упражнения



Ответы к упражнениям даны в приложении А.

1. Напишите программу, которая запрашивает температуру окружающего воздуха и выводит на экран слова "too hot", если температура выше 72 градусов (по Фаренгейту), а в противном случае выводит "too cold".

2. Модифицируйте программу из предыдущего упражнения так, чтобы она выводила на экран "too hot", если температура выше 75 градусов, "too cold" при температуре ниже 68 градусов и "just right!" при температуре от 68 до 75 градусов.

3. Напишите программу, которая читает список чисел (каждое из которых записано в отдельной строке), пока не будет прочитано число 999, после чего программа выводит сумму всех этих чисел. (Ни в коем случае не прибавляйте 999!) Например, если вы вводите 1, 2, з и 999, программа должна ответить цифрой 6 (1 + 2 + 3).

4. Напишите программу, которая читает список строковых значений (каждое из которых занимает отдельную строку) и выводит его на экран в обратном порядке, причем без проведения над списком операции reverse. (Вспомните, что <stdin> при использовании в списочном контексте читает список строковых значений, каждое из которых занимает отдельную строку.)

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

printf "%5g ”8д\п", $а, $Ь

которая выводит $а как пятизначное число, а $ь — как восьмизначное.

|     Назад     |     Вперед     |



| Содержание | Предисловие | Введение | Ссылки
| Глава 1 | Глава 2 | Глава 3 | Глава 4 | Глава 5 | Глава 6 | Глава 7 | Глава 8 | Глава 9 | Глава 10
| Глава 11 | Глава 12 | Глава 13 | Глава 14 | Глава 15 | Глава 16 | Глава 17 | Глава 18 | Глава 19
| Приложение А | Приложение Б | Приложение В | Приложение Г |


Содержание раздела