Цикл while в Rust
Цикл while работает, пока условие остаётся true. Это подходящий инструмент, когда ты знаешь, чего ждёшь, даже если не знаешь точно, сколько раз придётся повторить.
Простой цикл while
Заголовок раздела «Простой цикл while»fn main() { let mut count = 1;
while count <= 5 { println!("{count}"); count += 1; }}Вывод:
12345Условие (count <= 5) проверяется перед каждым проходом цикла. Как только оно становится false, цикл заканчивается — здесь это происходит, когда count становится 6.
while или loop
Заголовок раздела «while или loop»То же самое можно написать через loop и ручной if/break, но while выражает мысль прямее: «продолжай, пока это истинно». Оставь loop для случаев, когда условие остановки неудобно ставить в начало цикла.
// через while — ясно и по делуlet mut n = 0;while n < 3 { println!("{n}"); n += 1;}
// то же самое через loop — работает, но читать дольшеlet mut n = 0;loop { if n >= 3 { break; } println!("{n}"); n += 1;}Пример из жизни
Заголовок раздела «Пример из жизни»while часто используют, чтобы дождаться, пока значение дойдёт до цели:
fn main() { let mut balance = 100;
while balance < 200 { balance += 25; println!("Теперь на счёте {balance}"); }
println!("Цель достигнута!");}Вывод:
Теперь на счёте 125Теперь на счёте 150Теперь на счёте 175Теперь на счёте 200Цель достигнута!Условием может быть любое выражение, которое даёт bool, поэтому проверки можно объединять через && и || из урока Операторы, например while balance < 200 && months < 12.
В Rust нет do-while
Заголовок раздела «В Rust нет do-while»В некоторых языках есть цикл do { ... } while (condition). Он сначала выполняет тело, а потом проверяет условие, так что тело всегда выполняется хотя бы один раз. В Rust такого цикла нет. Вместо него используют loop и ставят проверку в конец.
Вот где это важно. Чтобы посчитать цифры в числе, можно делить его на 10, пока ничего не останется. Но у числа 0 тоже одна цифра, а обычный цикл while для него не выполнится ни разу:
fn main() { let number = 0;
// while сначала проверяет условие, поэтому для 0 не выполняется ни разу. let mut n = number; let mut digits = 0; while n > 0 { digits += 1; n /= 10; } println!("while: в числе {number} цифр: {digits}");
// loop с проверкой в конце выполняет тело хотя бы один раз. let mut n = number; let mut digits = 0; loop { digits += 1; n /= 10; if n == 0 { break; } } println!("loop: в числе {number} цифр: {digits}");}Вывод:
while: в числе 0 цифр: 0loop: в числе 0 цифр: 1Замени number на 4096 — и обе версии согласятся: 4 цифры. Разница видна только тогда, когда условие ложно с самого начала. Отсюда простое правило: если тело должно выполниться хотя бы раз, пиши loop с if ... { break; } внизу.
Есть ещё одна разновидность цикла while — while let, он работает, пока значение подходит под образец. О нём рассказано в уроке if let и while let.
Практика
Заголовок раздела «Практика»1. Складываем, пока не перевалит за 100
Заголовок раздела «1. Складываем, пока не перевалит за 100»Складывай 1 + 2 + 3 + … и остановись, как только сумма станет больше 100. Выведи, сколько чисел ты сложил, и саму сумму. Подсказка: нужны две mut-переменные: одна для следующего числа, другая для суммы.
Показать решение
fn main() { let mut next = 1; let mut total = 0;
while total <= 100 { total += next; next += 1; }
println!("Сложили чисел: {}, сумма: {total}", next - 1);}Вывод:
Сложили чисел: 14, сумма: 105После последнего прохода next уже ушла на шаг вперёд, поэтому мы выводим next - 1. Такие ошибки «на единицу» стоит проверять на маленьком примере в уме.
2. Делим пополам до 1
Заголовок раздела «2. Делим пополам до 1»Начни с 1000. Пока число больше 1, дели его на 2 (целочисленно) и выводи. В конце выведи, сколько понадобилось делений. Подсказка: n /= 2 делит n на 2 и отбрасывает остаток.
Показать решение
fn main() { let mut n = 1000; let mut steps = 0;
while n > 1 { n /= 2; steps += 1; println!("{n}"); }
println!("Чтобы дойти до 1, понадобилось делений: {steps}");}Вывод:
500250125623115731Чтобы дойти до 1, понадобилось делений: 9125 / 2 — это 62, а не 62.5, потому что оба числа целые. Именно поэтому цикл заканчивается ровно на 1.
while условие { ... }повторяется, пока условиеtrue; проверка идёт перед каждым проходом.- Убедись, что что-то внутри цикла рано или поздно сделает условие
false, иначе он будет работать вечно. - Предпочитай
while, а неloop, когда условие остановки естественно звучит как «пока выполняется X». - В Rust нет do-while. Если тело должно выполниться хотя бы раз, используй
loopс проверкойbreakв конце.
Проверь себя
Заголовок раздела «Проверь себя»Проверь себя
1. Какая классическая ошибка приводит к бесконечному циклу while?
2. Когда, судя по этой странице, стоит предпочесть while, а не loop?
3. Как написать цикл, тело которого всегда выполняется хотя бы один раз?
Результат: 0 / 3
Что почитать
Заголовок раздела «Что почитать»- Циклы с условием while — книга «Язык программирования Rust»: официальное введение, где
whileсравнивается сloop(перевод на русский). - while — Rust на примерах: FizzBuzz на цикле
while, который можно запустить (перевод на русский). - Predicate loops — The Rust Reference (на английском): точные правила работы цикла
while. - The
whilekeyword — документация стандартной библиотеки (на английском): краткая сводка оwhileиwhile letс примерами.