Листинг 5.14. Использование команды next для выборочной обработки элементов массива
#!perl -w
@array = (22, -5, -78, 4, -97, 10);
print "До обработки: @array\n";
foreach (@аrrау) {
next if $_ >= 0;
$_ = 0;
}
print "После обработки; @аrray\n";
Результат выполнения программы из листинга 5.14 будет следующим:
До обработки: 22 -5 -78 4 -97 10
После обработки; 22 0 0 4 0 10
Команда next с меткой прерывает выполнение текущей итерации цикла, в теле которого она находится, и
начинает новую итерацию цикла с указанной меткой, выполнив предварительно операторы блока continue этого
цикла, если таковой имеется (листинг 5.15).
Листинг 5.15. Команда next с меткой
#!perl -w
$out = 0;
OUT:
while ($out < 2) {
print "Начало внешнего цикла\n";
for($in=0; $in<=2; $in++) {
print "\$out: $out\t\$in: $in\n"; next OUT if $in == 1;
}
print "\$out: $out\n"; # Никогда не выполняется!
} continue {
print "Блок continue внешнего цикла\n";
$out++;
}
Вывод программы из листинга 5.15 будет следующим:
Начало внешнего цикла
$out: 0 $in: 0
$out: 0 $in: 1
Блок continue внешнего цикла
Начало внешнего цикла
$out: 1 $in: 0
$out: 1 $in: 1
Блок continue внешнего цикла
Обратите внимание, что количество итераций внутреннего цикла for равно двум, так как на его второй
итерации выполняется команда next OUT, прекращающая его выполнение и инициализирующая выполнение очередной
итерации внешнего никла OUT. Оператор печати этого цикла пропускается, выполняются операторы его блока
continue, проверяется условие, и, если оно истинно, тело цикла начинает снова выполняться. Таким образом,
оператор печати внешнего цикла OUT не выполняется ни одного раза, что подтверждается приведенным выводом
программы из листинга 5.15.
Подобно команде last, команда next не будет работать в цикле с постусловием, реализованным с помощью
конструкции do {...}. Однако небольшая хитрость позволяет и в этом случае задействовать команду next.
Для этого следует заключить все операторы в конструкции do {...} в фигурные скобки, создав тем самым блок,
в котором команда next уже сможет отработать:
do {{
next if $x == $y;
# какие-то операторы обработки
}} until $x++ > $z;
Для наглядности мы выделили фигурные скобки введенного блока полужирным шрифтом. При выполнении
оператора next управление должно быть передано на оператор, непосредственно следующий за добавленным
блоком. Такой оператор отсутствует, значит все операторы конструкции do {...} выполнены, и, следовательно,
необходимо снова вычислять выражение модификатора until. А это и означает, что осуществится переход на
следующую итерацию цикла.
Команда redo
Команда redo используется для повторного выполнения операторов тела цикла, не инициализируя
следующую итерацию. Если она должна выполниться (обычно в силу выполнения некоторого условия) во время
выполнения очередной итерации цикла, то расположенные за ней операторы тела цикла не выполняются, а
управление передается на первый оператор тела цикла, при этом новая итерация не инициализируется. Это
означает, что ни выражение изменения цикла for, ни операторы блока continue, если он задан, вместе с
выражением-условием циклов while/until не вычисляются, а в случае цикла foreach переменной цикла не
присваивается значение следующего элемента списка. Таким образом, при выполнении команды redo просто
снова начинают выполняться операторы тела цикла. Программа из листинга 5.16 демонстрирует использование
команды redo.
Листинг 5.16. Повторное вычисление тела цикла без инициализации новой итерации
#! perl -w
$notempty = "";
$total = "";
for (my $i=1; $i<=5; $i++) {
$line = <STDIN>; # Ввод строки
$total .= $line;
redo if $line =~ /^$/; # Возврат на чтение строки,
# если введена пустая
$notempty .= $line;
}
print "Все строки:\n$totalНenycтые:\n$notempty";
Эта программа ожидает ввода пользователем пяти непустых строк данных, сохраняя в переменной
$total все введенные строки (пустые и непустые) и накапливая в переменной $notempty введенные непустые
строки. Ввод пустой строки (пользователь просто нажал клавишу Enter, не введя ни одного символа)
инициирует команду redo. При этом последний оператор блока не выполняется (пустая строка не добавляется
в переменную $notempty), переменная цикла $i не меняет своего значения, и программа ожидает ввода
пользователем следующей строки. Таким образом, наша программа будет работать, пока пользователь не
введет пять непустых строк.
Если команда redo используется с меткой, то ее действие аналогично действию команды next с той
лишь разницей, что она просто передает управление на первый оператор тела цикла с указанной меткой,
не инициируя следующей итерации и не вычисляя операторов блока continue. В качестве иллюстрации
такого использования команды redo перепишем программу из листинга 5.16 таким образом, чтобы она
завершала свою работу, только если пользователь ввел подряд пять непустых строк (листинг 5.17).
Листинг 5.17. Команда redo с идентификатором метки
#!perl -w
$in = 1;
OUT:
while ($in) {
$total = "";
print "Введи подряд пять непустых строк:\n";
for (mу $i=1; $i<=5; $i++) {
$line = <STDIN>; # Ввод строки
$total .= $line;
redo OUT if $line =~ /^$/; # Возврат на цикл while,
# если введена пустея
# строка
$in = 0;
} # Конец цикла for
} # Конец цикла while
print "Все пять строк:\n$total":
В листинге 5.17 мы ввели внешний цикл OUT, в котором пользователя просят ввести подряд пять непустых
строк. Если он все-таки ввел пустую строку, то команда redo инициирует очередное выполнение операторов
цикла while, не вычисляя выражение-условие. Если введено подряд пять непустых строк, то осуществляется
переход на следующую итерацию цикла while. При этом вычисляется его выражение-условие, которое будет
ложно (переменная $in имеет значение 0), это означает, что цикл while завершен, а следовательно,
завершена и вся программа.