while и repeat-while
В прошлом уроке бегун заранее знал, сколько кругов бежать. Бывает иначе. Тренер говорит: «Бегай, пока не наберёшь километр». Сколько это кругов, бегун заранее не считает. Перед каждым кругом он смотрит на счётчик метров и решает, выходить ли на следующий.
Так работает цикл while: он повторяет тело, пока условие истинно, и проверяет условие перед каждой итерацией. Вот тот самый километр:
var meters = 0
var laps = 0
while meters < 1000 {
meters += 400
laps += 1
}
print(laps, meters) // 3 1200Давайте пройдём по итерациям:
- Перед первым кругом
metersравна0, условие0 < 1000истинно, и тело выполняется: вmetersстановится400, вlaps—1. 400 < 1000— истинно, второй круг:800метров и2круга.800 < 1000— истинно, третий круг:1200метров и3круга.1200 < 1000— ложно, и цикл заканчивается без нового круга.printпечатает3 1200.
Сначала проверка, потом круг
Строка while meters < 1000 устроена как if: после слова while идёт условие типа Bool, а тело стоит в фигурных скобках. Круглые скобки вокруг условия не нужны.
Главное в while — порядок действий. Сначала проверка, потом итерация. Цикл заканчивается после той итерации, на которой условие стало ложным. Поэтому после цикла в meters лежит 1200, а не 1000: бегун не сходит с дорожки посреди круга.
Если условие ложно с самого начала, тело не выполнится ни разу. С var meters = 2000 программа сразу напечатает 0 2000.
Здесь картинка неточна: живой бегун хотя бы раз выйдет на дорожку, а while может не выполнить тело совсем.
Цикл repeat-while
Иногда тело должно выполниться хотя бы раз. Для этого есть цикл repeat-while: сначала круг, потом проверка. В других языках такой цикл записывают через do и while, а в Swift он начинается со слова repeat.
Сравним два цикла с одним и тем же ложным условием:
var x = 10
while x < 5 {
x += 1
}
print(x) // 10
repeat {
x += 1
} while x < 5
print(x) // 11Разберём по шагам:
while x < 5начинает с проверки:10 < 5ложно, тело не выполняется, иprintпечатает10.repeatначинает с тела:xстановится11.- Только потом
while x < 5проверяет условие:11 < 5ложно, и цикл заканчивается. printпечатает11: телоrepeatвыполнилось ровно один раз.
Классическая задача для repeat-while — посчитать цифры числа. Каждая итерация отбрасывает последнюю цифру, пока число не станет нулём:
var number = 2026
var digits = 0
repeat {
digits += 1
number = number / 10
} while number > 0
print(digits) // 4Деление целых чисел отбрасывает остаток, поэтому 2026 превращается в 202, потом в 20, 2 и 0.
Почему здесь repeat, а не while? У нуля одна цифра. С var number = 0 этот цикл выполнит тело один раз, и программа напечатает 1. Цикл while number > 0 с тем же телом не выполнил бы его ни разу, и программа напечатала бы 0.
На собеседовании часто спрашивают, чем while отличается от repeat-while. Ответ: while проверяет условие перед телом и может не выполнить его ни разу, а repeat-while проверяет после тела, поэтому тело выполняется хотя бы раз.
Частая ошибка
В теле цикла забыли изменить переменную из условия:
var i = 1
while i <= 3 { // ✗
print(i)
}Условие i <= 3 всегда истинно, потому что i всегда равна 1. Программа печатает 1 снова и снова и сама не остановится. Такой цикл называют бесконечным: бегун крутит круги, а счётчик стоит на месте.
Остановите программу вручную: в терминале — сочетанием клавиш Ctrl+C, в Xcode — кнопкой «Stop». В Swift Playgrounds на время работы программы кнопка запуска становится кнопкой остановки. Добавьте i += 1 в конец тела, и цикл напечатает 1, 2 и 3.
Главное
whileпроверяет условие перед каждой итерацией: если оно ложно с самого начала, тело не выполнится ни разу.- Цикл заканчивается после той итерации, на которой условие стало ложным.
repeat-whileпроверяет условие после тела, поэтому тело выполняется хотя бы раз.- Если тело не меняет переменную из условия, цикл становится бесконечным.