🦀 Rust

Цикл while и do-while в Rust 1.75: подробное руководство

Цикл while и do-while в Rust

Что такое цикл и зачем он нужен?

Представь, что тебе нужно 100 раз написать в тетради: «Я буду хорошо учиться». Писать это 100 раз вручную — очень скучно и долго. В программировании для таких повторяющихся действий существуют циклы. Цикл — это команда компьютеру: «Делай это снова и снова, пока не наступит определённое условие».

Сегодня мы познакомимся с двумя видами циклов: while и do-while. Они помогают повторять действия, когда мы не знаем заранее, сколько раз их нужно повторить. Например, робот-шахтёр собирает кристаллы, пока его сумка не наполнится — он не знает, сколько кристаллов ему встретится.

Цикл while

Цикл while работает очень просто: «Пока условие верно — делай действие». Как только условие становится ложным, цикл останавливается.

Синтаксис цикла while в Rust:

while условие {
    // код, который будет повторяться
}

Важно: условие проверяется перед каждым выполнением тела цикла. Если условие сразу ложное, цикл не выполнится ни разу.

Пример 1: Обратный отсчёт

Доктор Элара Вэнс запускает машину времени с начальной координаты n и ведёт обратный отсчёт до 1.

use std::io;

fn main() {
    println!("Введите начальную временную координату:");
    let mut input = String::new();
    io::stdin().read_line(&mut input).expect("Ошибка чтения");
    let mut n: i32 = input.trim().parse().expect("Введите число");

    println!("Запуск обратного отсчёта:");
    while n > 0 {
        println!("{}...", n);
        n = n - 1; // уменьшаем число на 1
    }
    println!("Время пошло вперёд!");
}

Как это работает:
Пользователь вводит число (например, 5). Цикл проверяет: «5 > 0? Да!» — печатает 5, затем 4, 3, 2, 1. Когда n становится 0, условие n > 0 ложно, и цикл завершается.

Цикл do-while (или loop с проверкой в конце)

В Rust нет отдельного ключевого слова do-while, как в других языках. Но его можно сделать с помощью loop и break.

Главное отличие от while: тело цикла выполняется хотя бы один раз, а потом проверяется условие. Синтаксис:

loop {
    // код, который выполняется
    if !условие {
        break; // выходим из цикла, если условие стало ложным
    }
}

Пример 2: Секретный агент

Агент получает зашифрованные коды. Нужно продолжать их обрабатывать, пока не встретится код 0 (сигнал остановки). При этом первый код нужно обработать обязательно.

use std::io;

fn main() {
    println!("Вводите числовые коды (0 — стоп):");
    loop {
        let mut input = String::new();
        io::stdin().read_line(&mut input).expect("Ошибка чтения");
        let code: i32 = input.trim().parse().expect("Введите число");

        if code == 0 {
            println!("Сигнал остановки получен. Миссия завершена.");
            break; // выходим из цикла
        }
        println!("Обработан код: {}", code * 2); // шифруем код
    }
}

В этом примере код обрабатывается до проверки условия, поэтому даже если сразу ввести 0 — программа сначала обработает его (умножит на 2), а потом остановится.

Разбор типичных задач

Задача 1: Робот-шахтёр

Робот собирает кристаллы. Каждый кристалл даёт случайное количество энергии от 10 до 30. Нужно собирать, пока энергия не станет ≥ 100.

use std::io;

fn main() {
    let mut energy = 0;
    let mut crystals_collected = 0;

    println!("Робот-шахтёр начал сбор кристаллов!");
    while energy < 100 {
        // Ввод энергии от кристалла (имитируем сканирование)
        println!("Введите энергию найденного кристалла (10-30):");
        let mut input = String::new();
        io::stdin().read_line(&mut input).expect("Ошибка");
        let crystal_energy: i32 = input.trim().parse().expect("Число!");

        energy += crystal_energy;
        crystals_collected += 1;
        println!("Собран кристалл! Энергия: {}. Всего: {}", crystal_energy, energy);
    }
    println!("Сумка полна! Собрано {} кристаллов. Энергия: {}", crystals_collected, energy);
}

Задача 2: Юный садовод

Алекс хочет узнать, через сколько дней росток достигнет нужной высоты. Если росток уже выше или равен цели — ответ 0 дней.

use std::io;

fn main() {
    println!("Введите начальную высоту ростка (см):");
    let mut input = String::new();
    io::stdin().read_line(&mut input).expect("Ошибка");
    let mut height: f64 = input.trim().parse().expect("Число!");

    println!("Во сколько раз он растёт каждый день?");
    input.clear();
    io::stdin().read_line(&mut input).expect("Ошибка");
    let growth_rate: f64 = input.trim().parse().expect("Число!");

    println!("Какой высоты вы хотите его вырастить?");
    input.clear();
    io::stdin().read_line(&mut input).expect("Ошибка");
    let target: f64 = input.trim().parse().expect("Число!");

    let mut days = 0;
    while height < target {
        height *= growth_rate;
        days += 1;
        println!("День {}: высота {:.1} см", days, height);
    }
    println!("Росток достиг {:.1} см через {} дней!", height, days);
}

Частые ошибки новичков

  • Бесконечный цикл: забыли изменить переменную в условии. Например, написали while n > 0 { println!("{}", n); } без n = n - 1. Компьютер будет печатать вечно!
  • Ошибка на 1 (off-by-one): неправильное условие. Например, нужно >= 100, а написали > 100 — цикл закончится раньше.
  • Путаница с типом данных: если переменная целая (i32), а вы пытаетесь использовать дробные числа — Rust выдаст ошибку.
  • Забыли про break в loop: цикл с loop без break будет работать бесконечно.

Итоговый пример: Волшебная экспедиция

Вы находите Артефакт Силы. Он начинает светиться, и вы понимаете: нужно вводить заклинания (числа), пока их сумма не достигнет ровно 100. Если сумма станет больше 100 — артефакт перегреется и сломается!

use std::io;

fn main() {
    println!("🔮 Артефакт Силы ждёт заклинаний!");
    println!("Вводите числа. Сумма должна стать ровно 100.");
    println!("Если превысите — артефакт сломается!");

    let mut sum = 0;

    loop {
        println!("Текущая сила: {}. Введите заклинание:", sum);
        let mut input = String::new();
        io::stdin().read_line(&mut input).expect("Ошибка");
        let spell: i32 = input.trim().parse().expect("Введите число!");

        sum += spell;

        if sum == 100 {
            println!("🎉 Ура! Артефакт активирован! Сумма ровно 100!");
            break;
        } else if sum > 100 {
            println!("💥 О нет! Артефакт перегрелся! Сумма стала {}!", sum);
            break;
        } else {
            println!("Сила растёт... ({} ед.)", sum);
        }
    }
    println!("Экспедиция завершена.");
}

Заключение

Циклы while и loop (do-while) — твои верные помощники, когда нужно повторять действия, но ты не знаешь точное количество повторений. Главное — не забывай менять условие внутри цикла, чтобы он не стал бесконечным! Практикуйся на задачах с роботами, садоводами и агентами — и ты быстро научишься управлять циклами в Rust.