Модификаторы простых операторов
Каждый простой оператор может быть
снабжен модификатором, представляющим ключевое СЛОВО if, unless, while,
until ИЛИ foreach, за которым следует выражение-условие. В самом операторе модификатор
стоит непосредственно за выражением, составляющим простой оператор, перед завершающим
символом точка с запятой. Каждый простой оператор может иметь только один
модификатор. Семантически роль модификатора сводится к тому, что оператор
вычисляется при выполнении условия, определяемого модификатором. Например, следующий
оператор присваивания
$n = $l/$m if $т != 0;
с модификатором if будет выполнен при условии, что переменная $т не равна о.
Общий синтаксис простого оператора с модификатором имеет следующий вид:
ВЫРАЖЕНИЕ ключ_слово_модификатора [(]ВЫРАЖЕНИЕ-УСЛОВИЕ [)];
Модификаторы if и unless употребляются
в прямом смысле их английского значения. Простой оператор с модификатором If
выполняется, если ВЫРАЖЕНИЕ-УСЛОВИЕ истинно. Семантически простой оператор
ВЫРАЖЕНИЕ if ВЫРАЖЕНИЕ-УСЛОВИЕ;
эквивалентен следующему оператору условия:
if(ВЫРАЖЕНИЕ-УСЛОВИЕ) { ВЫРАЖЕНИЕ; }
Замечание
В этом разделе мы представляем
эквивалентные простым операторам с модификаторами соответствующие составные
операторы языка Perl. Их синтаксис и применение будут детально разобраны в следующих
параграфах, но мы уверены, что читатель поймет их и без дополнительных объяснений.
Во всяком случае всегда можно вернуться к данному разделу, прочитав разделы,
посвященные составным операторам языка Perl.
Модификатор unless является прямой
противоположностью модификатора if: простой оператор выполняется, если ВЫРАЖЕНИЕ-УСЛОВИЕ
не истинно. Общий синтаксис простого оператора с модификатором unless имеет
следующий вид:
ВЫРАЖЕНИЕ unless ВЫРАЖЕНИЕ-УСЛОВИЕ;
Это всего лишь удобная форма записи оператора условия
if( ! ВЫРАЖЕНИЕ-УСЛОВИЕ) { ВЫРАЖЕНИЕ; }
Замечание
ВЫРАЖЕНИЕ-УСЛОВИЕ вычисляется
в булевом контексте: оно трактуется как Ложь, если равно о или пустой строке
" ", и Истина — в любом другом случае.
Использование модификаторов if
и unless показано в примере 5.1 — простой программе решения квадратного уравнения.
# peri -w
$а = <STDIN>;
$b = <STDIN>;
$с = <STDIN>;
$d = $b**2 - 4*$a*$c; # Вычисление дискриминанта уравнения
# Вычисление корней, если дискриминант положителен
( $xl =.(-$b+sqrt $d)/$a/2, $x2 = (-$b-sqrt $d)/$a/2 ) unless $d < 0;
# Печать результатов
print "Коэффициенты:\п а = $а b = $b с = $с"; print "\tPenieHHe:\n\t$xl\t$x2"
if defined $xl; print "^Решения нет!" unless defined $xl;
Наша программа решения квадратного уравнения, конечно, примитивна. Из всех возможных
проверок в ней проверяется на положительность только дискриминант квадратного
уравнения, хотя стоило бы проверить на нуль значение вводимого пользователем
с клавиатуры старшего коэффициента уравнения, сохраняемого в переменной $а.
Модификатор unless используется в операторах вычисления корней и печати сообщения
об отсутствии решения. Обратите внимание, что в операторе печати проверяется,
определена ли переменная $xi, а будет она определена только в случае положительности
дискриминанта $d. В модификаторе if оператора печати корней уравнения также
проверяется, определена ли переменная $xl.
Модификаторы while и until
Эти два модификатора немного сложнее
модификаторов if и unless. Они реализуют процесс циклического вычисления простого
оператора. Их синтаксис таков:
ВЫРАЖЕНИЕ while ВЫРАЖЕНИЕ-УСЛОВИЕ; ВЫРАЖЕНИЕ until ВЫРАЖЕНИЕ-УСЛОВИЕ;
Модификатор while повторно вычисляет ВЫРАЖЕНИЕ, пока истинно ВЫРАЖЕНИЕ-УСЛОВИЕ.
Модификатор until противоположен модификатору while: ВЫРАЖЕНИЕ повторно вычисляется
до момента, когда ВЫРАЖЕНИЕ-УСЛОВИЕ станет истинным, иными словами оно вычисляется,
пока ВЫРАЖЕНИЕ-УСЛОВИЕ ложно.
Семантически эти модификаторы простых операторов эквивалентны следующим составным
операторам цикла:
while(ВЫРАЖЕНИЕ-УСЛОВИЕ) { ВЫРАЖЕНИЕ; } until(ВЫРАЖЕНИЕ-УСЛОВИЕ) { ВЫРАЖЕНИЕ;
}
Пример 5.2 дает представление о том, как работают модификаторы повтора while
И until.
# peri -w $first = 10;
• $second = 10; $first++ while $first < 15; # $first увеличивается, пока
не станет
# равной 15
—$second until $second < 5; # $second уменьшается, пока не станет
# равной 4
print "\$first $first\n"; print "\$second $second\n";
Оператор увеличения на единицу переменной $first будет выполняться, пока выражение
$ first < 15 остается истинным. Когда значение переменной $first станет равным
15, выражение модификатора while становится ложным, и оператор завершает работу.
Аналогично работает и следующий оператор уменьшения переменной $second на единицу.
Единственное отличие от предыдущего оператора заключается в том, что он выполняется,
пока выражение $ second < 5 модификатора until остается ложным. Два оператора
печати выведут на экран значения переменных $first и $second равными соответственно
15 и 4.
Замечание
Модификаторы повтора следует применять
к простым операторам, вычисление которых приводит к изменению условий модификаторов.
Если это не так, то простой оператор либо вообще не будет выполнен, либо будет
выполняться бесконечно. Например, следующий оператор
print $var while $var < 15;
либо ни разу не напечатает значение переменной $var (если $var > =15), либо
будет печатать бесконечно (если $var < 15). В последнем случае произойдет
так называемое зацикливание и только нажатием комбинации клавиш <Ctrl>+<C>
можно будет остановить выполнение этого оператора.
Модификаторы while и until сначала
проверяют истинность или ложность своих выражений-условий, а потом, в зависимости
от полученного результа, либо выполняют простой оператор, либо нет. Таким образом,
они реализуют цикл с предусловием, при котором оператор, для которого
они являются модификаторами, может не выполниться ни одного раза.
Существует единственное исключение из этого правила, когда модификаторы повтора
применяются к синтаксической конструкции do <}, которая не является оператором
(хотя внешне и похожа), а относится к термам (см. главу 4). Поэтому,
если ее завершить точкой с запятой, то такая конструкция будет являться простым
оператором, к которому можно применять все возможные модификаторы Perl. Семантика
этой конструкции заключается в том, что она вычисляет операторы, заданные в
фигурных скобках {}, и возвращает значение последнего выполненного оператора.
Так вот, если к простому оператору do {}; применить модификаторы повтора, то
сначала выполнятся операторы конструкции do {}, а потом будет проверено условие
модификатора. Это позволяет написать следующий простой оператор, который сначала
осуществит ввод с клавиатуры, а потом проверит введенную информацию на совпадение
с символом завершения ввода:
$string = ""; do{
$line = <STDIN>;
$string .= $line; I until $line eq ".\n";
Этот фрагмент кода будет накапливать вводимые пользователем строки в переменной
$string до тех пор, пока не будет введена строка, состоящая из единственного
символа точки, после чего оператор do{} until; завершит свою работу. Обратите
внимание, что проверка в модификаторе until ведется на совпадение со строкой
". \п", в которой присутствует символ перехода на новую строку. Дело
в том, что операция ввода <STDIN> передает этот символ в программу, так
как пользователь именно этим символом завершает ввод строки (нажатие клавиши
<Enter>).
Модификатор foreach
Модификатор foreach ВЫРАЖЕНИЕ относится
к модификаторам цикла. Он повторно выполняет простой оператор, осуществляя итерации
по списку значений, заданному в ВЫРАЖЕНИЕ. На каждой итерации выбранный элемент
списка присваивается встроенной переменной $_, которую можно использовать в
простом операторе для получения значения выбранного элемента списка. Например,
следующий оператор распечатает все элементы массива @т:
print "$_ " foreach @т;
Общий синтаксис простого оператора с модификатором foreach следующий:
ВЫРАЖЕНИЕ foreach ВЫРАЖЕНИЕ-СПИСОК;
Простой оператор с модификатором foreach всего лишь удобная форма записи составного
оператора jforeach:
foreach (ВЫРАЖЕНИЕ-СПИСОК) { ВЫРАЖЕНИЕ; }
Эта форма составного оператора foreach в качестве переменной цикла использует
встроенную переменную $_ (см. раздел 5.4.3). Обратим внимание читателя
на то, что ВЫРАЖЕНИЕ-список вычисляется в списковом контексте, поэтому все используемые
в нем переменные ведут себя так, как они должны вести в списковом контексте.
Например, хеш-массив представляет обычный список, составленный из последовательности
его пар ключ/значение. Следующий фрагмент кода
%hash = ( one=>6, two=>8, three=>10 ); print "$_ "
foreach %hash;
напечатает строку
three 10 two 8 one 6
Эта строка и есть тот простой список, который возвращает хеш в списковом контексте.
Относительно модификатора foreach (это же относится и к его эквивалентному оператору
foreach) следует сказать одну важную вещь. Дело в том, что переменная $_ является
не просто переменной, в которой хранится значение элемента списка текущей итерации,
она является синонимом имени этого элемента. Это означает, что любое изменение
переменной $_ в простом операторе приводит к изменению текущего элемента списка
в цикле. Пример 5.3 демонстрирует, как просто можно умножить каждый элемент
массива на некоторое число:
# peri -w
§array = (1, 2, 3);
$_ *= 2 foreach Sarray; # Умножение каждого элемента на 2.
print "@array"; # Напечатает строку: 246