Перейти к содержимому
Теория · Циклы · урок 3 из 5

while и repeat-while

В прошлом уроке бегун заранее знал, сколько кругов бежать. Бывает иначе. Тренер говорит: «Бегай, пока не наберёшь километр». Сколько это кругов, бегун заранее не считает. Перед каждым кругом он смотрит на счётчик метров и решает, выходить ли на следующий.

Так работает цикл while: он повторяет тело, пока условие истинно, и проверяет условие перед каждой итерацией. Вот тот самый километр:

SWIFT
var meters = 0
var laps = 0
while meters < 1000 {
    meters += 400
    laps += 1
}
print(laps, meters) // 3 1200

Давайте пройдём по итерациям:

  1. Перед первым кругом meters равна 0, условие 0 < 1000 истинно, и тело выполняется: в meters становится 400, в laps — 1.
  2. 400 < 1000 — истинно, второй круг: 800 метров и 2 круга.
  3. 800 < 1000 — истинно, третий круг: 1200 метров и 3 круга.
  4. 1200 < 1000 — ложно, и цикл заканчивается без нового круга.
  5. 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.

Сравним два цикла с одним и тем же ложным условием:

SWIFT
var x = 10
while x < 5 {
    x += 1
}
print(x) // 10
repeat {
    x += 1
} while x < 5
print(x) // 11

Разберём по шагам:

  1. while x < 5 начинает с проверки: 10 < 5 ложно, тело не выполняется, и print печатает 10.
  2. repeat начинает с тела: x становится 11.
  3. Только потом while x < 5 проверяет условие: 11 < 5 ложно, и цикл заканчивается.
  4. print печатает 11: тело repeat выполнилось ровно один раз.

Классическая задача для repeat-while — посчитать цифры числа. Каждая итерация отбрасывает последнюю цифру, пока число не станет нулём:

SWIFT
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 проверяет после тела, поэтому тело выполняется хотя бы раз.

Частая ошибка

В теле цикла забыли изменить переменную из условия:

SWIFT
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 проверяет условие после тела, поэтому тело выполняется хотя бы раз.
  • Если тело не меняет переменную из условия, цикл становится бесконечным.