Rust: с нуля до своего органайзера Урок 13 из 20
Повторение действий
Урок 13. Выполнить действие несколько раз без пропусков и бесконечного повторения.
Текст переведён с помощью ИИ.
Предварительно: уроки 1–12. Если непонятны переменные, вернитесь к уроку 9.
Зачем это нужно
До сих пор каждая строка выполнялась один раз, если до неё доходила программа. Цикл повторяет блок. Один проход называется итерацией. Как ежедневная отметка в календаре: правило одно, дни меняются. Но календарь сам завершится на последней странице, а программа без условия остановки может работать бесконечно.
Начнём с плана: три дня по десять минут на задачи. Это расчёт заданных данных, а не ожидание трёх настоящих дней. Вспомните mut из урока 9 и условия из урока 12.
Запуск примера
Работаем в проекте organizer, созданном в уроке 6, в папке с Cargo.toml. Сохраните свою предыдущую работу отдельно. Замените весь src/main.rs первым примером ниже, сохраните файл и выполните cargo run в терминале этой папки. Как объяснялось в уроке 6, команда собирает и запускает программу. Остальные файлы менять не нужно; зависимости не добавляем. Каждый следующий полный пример также заменяет файл целиком. В блоке результата показан только вывод программы, без сообщений Cargo. Сначала предскажите его, потом запускайте.
Новая запись до запуска: for day in 1..=3 берёт по очереди числа из диапазона от 1 до 3 включительно. for начинает повторение, day — имя текущего числа, in указывает источник, а ..= включает правую границу. Представьте три клетки календаря, по которым последовательно проходит палец; программа не ждёт настоящих дней. Каждое прохождение блока { ... } — один оборот цикла.
fn main() {
let mut total_minutes: u32 = 0;
for day in 1..=3 {
println!("День: {day}");
total_minutes = total_minutes + 10;
}
println!("Всего минут: {total_minutes}");
}
День: 1
День: 2
День: 3
Всего минут: 30
Разбор
for означает цикл перебора, in — «из»: для каждого значения диапазона выполняется блок. Диапазон задаёт последовательность границами. 1..=3 включает 1, 2, 3; 1..3 включает только 1 и 2. Знак = в ..= включает правую границу, он здесь не присваивание. Для этих возрастающих целочисленных диапазонов 3..3 и 3..1 пусты: обратный отсчёт так не задаётся.
day создаётся циклом для текущего значения и доступен внутри его блока. Ручное увеличение day не нужно. total_minutes — накопитель: переменная, собирающая результат проходов. Объявляем её до цикла, иначе она каждый раз начиналась бы с нуля. total_minutes = total_minutes + 10 читает старое значение, прибавляет 10 и записывает новое. После проходов это 10, 20, 30. Внешнее println! выполняется один раз.
Когда нужен while или loop
while означает «пока»: условие проверяется до каждого прохода. Если с самого начала оно ложно, блок не выполнится ни разу. loop повторяет блок без условия. break немедленно выходит из ближайшего цикла; continue пропускает оставшуюся часть текущего прохода и переходит к следующему. У while при этом снова проверяется условие, а у for берётся следующее значение.
Следующий пример — отдельная программа: временно замените весь src/main.rs, а не добавляйте вторую main.
fn main() {
let mut remaining: u32 = 3;
while remaining > 0 {
println!("Осталось: {remaining}");
remaining = remaining - 1;
}
let mut attempt: u32 = 0;
loop {
attempt = attempt + 1;
if attempt == 2 {
continue;
}
println!("Попытка: {attempt}");
if attempt == 3 {
break;
}
}
}
Осталось: 3
Осталось: 2
Осталось: 1
Попытка: 1
Попытка: 3
В while счётчик remaining уменьшается до нуля: только это изменение делает условие ложным. В loop attempt означает номер попытки. Он увеличивается до возможного continue: второй проход не печатается, а третий заканчивается break. Для такого известного набора проще for; loop здесь показывает управление повторением.
Как не зависнуть
Если убрать уменьшение remaining, while никогда не закончит работу. Если поставить увеличение attempt после continue, можно застрять на одном значении. Перед запуском найдите, что приближает цикл к выходу. Если случайно запустили бесконечную печать, нажмите Ctrl+C в терминале: это прерывает программу, но не исправляет её код.
Ошибка на единицу — неверная граница: 1..3 даёт два прохода, а не три. Проверьте на бумаге первый и последний элементы прежде, чем менять код.
Опорная карта
Начальное состояние → очередное значение или условие → блок → изменение → завершение.
Проверьте понимание
- Сколько проходов у
0..3и0..=3? - Чем
breakотличается отcontinue? - Что произойдёт, если объявить накопитель внутри цикла?
Сверка: 3 и 4; выход из цикла и переход к следующему проходу; накопитель будет создаваться заново, итог всех проходов не сохранится.
Задание
Обязательное. Составьте план на дни 1–5 включительно: по 15 минут, но день 3 пропустите через continue. Напечатайте только дни 1, 2, 4, 5 и «Всего минут: 60». Не заменяйте накопление готовым числом.
Проверьте границу. Временно используйте 1..1: не должно быть ни одного дня, итог — 0. Верните 1..=5. Объясните, почему проверка дня должна стоять до печати и прибавления.
Подсказка
Счётчик минут объявите перед for. Проверку day == 3 разместите первой в блоке. Эталон не считает пропущенный день.
Эталон после самостоятельной попытки
fn main() {
let mut total_minutes: u32 = 0;
for day in 1..=5 {
if day == 3 {
continue;
}
println!("День: {day}");
total_minutes = total_minutes + 15;
}
println!("Всего минут: {total_minutes}");
}
День: 1
День: 2
День: 4
День: 5
Всего минут: 60
Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом
Комментарии (0)
Войдите, чтобы оставить комментарий →
Пока нет комментариев. Будьте первым.