Операторы цикла
Известно, что для реализации любого алгоритма достаточно трех структур управления: последовательного выполнения, ветвления по условию и цикла с предусловием. Любой язык программирования предоставляет в распоряжение программиста набор всех трех управляющих конструкций, дополняя их для удобства программирования другими конструкциями: цепочки ветвления и разнообразные формы цикла с предусловием, а также циклы с постусловием.
Мы уже познакомились с операторами ветвления Perl, а теперь пришло время узнать, какие конструкции цикла можно применять в Perl. Их всего три: while, for и foreach. Все они относятся к классу составных операторов и, естественно, определяются в терминах блоков БЛОК.
Циклы while и until
Цикл while предназначен для повторного вычисления блока операторов, пока остается истинным задаваемое в нем выражение-условие. Его общий синтаксис имеет две формы:
МЕТКА while (ВЫРАЖЕНИЕ) БЛОК
МЕТКА while (ВЫРАЖЕНИЕ) БЛОК continue БЛОК1
Все операторы цикла могут быть снабжены не обязательными метками. В Perl метка представляет правильный идентификатор, завершающийся двоеточием ":". Она важна для команды перехода next, о которой мы поговорим в следующем разделе.
Оператор while выполняется по следующей схеме. Вычисляется выражения-условия ВЫРАЖЕНИЕ. Если оно истинно, то выполняются операторы БЛОК. В противном случае оператор цикла завершает свою работу и передает управление следующему после него оператору программы (цикл 1 примера 5.5). Таким образом, оператор цикла while является управляющей конструкцией цикла с предусловием: сначала проверяется условие завершения цикла, а потом только тело цикла, определяемое операторами БЛОК. Поэтому может оказаться, что тело цикла не будет выполнено ни одного раза, если при первом вхождении в цикл условие окажется ложным (цикл 3 примера 5.5).
Вместо ключевого слова while можно использовать ключевое слово until. В этом случае управляющая конструкция называется циклом until, который отличается от разобранного цикла while тем, что его тело выполняется, только если выражение условия ложно (цикл 2 примера 5.5).
# peri -w
# цикл 1
$i = 1;
while <$i•<= 3) {
$a[$i] = l/$i; # Присвоить значение элементу массива
++$i; >
print "Переменная цикла \$i = $i\n"; # $i = 4 print "Массив \@a: @a\n"; # @a = (I, 0.5. 0.333333333333333)
# цикл 2, эквивалентный предыдущему
$i = 1;
until ($i > 3) {
$a[$i] = l/$i; # Присвоить значение элементу массива
++$i; }
print "Переменная цикла \$i = $i\n"; # $i = 4 print "Массив \@a: @a\n"; # @a = (1, 0.5. 0.333333333333333)
# цикл З, тело цикла не выполняется ни одного раза
$i = 5;
while ($i-<= 3) {
$a[$i] = l/$i;
++$i; } print "Переменная цикла \$i = $i\n"; # $i = 5
# цикл 4, бесконечный цикл (не изменяется выражение условия)
$i = 1;
while ($i <= 3) {
$a[$i] = l/$i; } .
Обратим внимание на то, что в теле цикла должны присутствовать операторы, вычисление которых приводит к изменению выражения условия. Обычно это операторы, изменяющие значения переменных, используемых в выражении условия. Если этого не происходит, то цикл while или until будет выполняться бесконечно (цикл 4 примера 5.5).
Замечание
Цикл с постусловием реализуется применением модификатора while к конструкции do{), и рассматривался нами в разделе 5.2.2 " Модификаторы while и until".
Блок операторов БЛОК!, задаваемый после ключевого слова continue, выполняется всякий раз, когда осуществляется переход на выполнение новой итерации. Это происходит после выполнения последнего оператора тела цикла или при явном переходе на следующую итерацию цикла командой next. Блок continue на практике используется редко, но с его помощью можно строго определить цикл for через оператор цикла while.
Пример 5.6 демонстрирует использование цикла while для вычисления степеней двойки не выше шестнадцатой. В этом примере оператор цикла while функционально эквивалентен циклу for. Блок continue выполняется всякий раз по завершении очередной итерации цикла, увеличивая переменную $i на единицу. Он эквивалентен выражению увеличения/уменьшения оператора for.
# peri -w
# Вычисление степеней числа 2 $1 = I;
while ($i <= 16) {
print "2 в степени $i: ", 2**$i, "\n"; } continue {
++$i; f Увеличение переменной $i перед выполнением следующей итерации }