Shanraq.org Shanraq.org
match: обработать каждый вариант
IT

Rust: с нуля до своего органайзера Урок 30 из 35

match: обработать каждый вариант

Урок 30. Прочитать состояние задачи полностью и заметить забытый вариант до запуска программы.

Текст переведён с помощью ИИ.

Предварительно: уроки 12, 14, 19 и 29. Если Status::Doing(15) непонятен, повторите урок 29.

Образ и опорная карта

Дежурный получает карточку с одним из трёх штампов. Чтобы действие было определено всегда, на столе лежит инструкция для каждого штампа. Сопоставление с образцом означает: проверить форму значения и, если форма содержит данные, дать им имена. match выбирает ровно одну подходящую ветку. Образ ограничен: Rust проверяет полноту вариантов ещё при компиляции, а бумажный дежурный может забыть инструкцию.

Значение → match → образцы → одна ветка → результат. Ветки проверяются сверху вниз. Status::Doing(minutes) — образец для варианта Doing с новым именем minutes для внутреннего числа. => отделяет образец от результата или действия. В отличие от if с несколькими независимыми условиями, match требует охватить все возможные варианты; иначе код не компилируется. Можно использовать _ как образец «любой оставшийся случай», но тогда новое состояние позже тоже попадёт в эту ветку.

Результат из полного разбора

Сохраните прежний src/main.rs проекта organizer, замените файл целиком и выполните cargo run в папке с Cargo.toml. Других файлов и зависимостей нет. Предскажите вывод до запуска.

matchвыражение: его можно присвоить переменной. Здесь оно отвечает на узкий вопрос «сколько минут сейчас числится в работе?». Для Planned и Done ответ 0, потому что работа сейчас не идёт. Для Doing(minutes) ответ — число внутри варианта. Все три ветки возвращают u32, поэтому у всего выражения один тип. После закрывающей } стоит ;, завершающая объявление let.

enum Status {
    Planned,
    Doing(u32),
    Done,
}

fn main() {
    let status = Status::Doing(10);
    let active_minutes: u32 = match status {
        Status::Planned => 0,
        Status::Doing(minutes) => minutes,
        Status::Done => 0,
    };
    println!("Сейчас в работе: {active_minutes} мин");
}
Сейчас в работе: 10 мин

Ветки не выполняются все подряд: выбирается одна, соответствующая значению. Если вместо Doing(10) поставить Done, результат будет 0. Это число не означает, что на завершённую задачу вообще не тратили время; мы считаем только текущую работу.

Забытая ветка и _

Если убрать Done, компилятор остановит отдельный пример с E0004. Он не позволит оставлять это состояние без результата:

enum Status { Planned, Doing(u32), Done }
fn main() {
    let status = Status::Done;
    let minutes = match status {
        Status::Planned => 0,
        Status::Doing(value) => value,
    };
    println!("{minutes}");
}

_ — образец, которому подходит любое ещё не обработанное значение. Например, Status::Done => ... и _ => ... покроют все состояния. Но если позднее добавить новый вариант, _ скроет его от проверки полноты. Для состояний органайзера, где каждому состоянию нужен свой смысл, перечисляйте варианты явно. _ полезен, когда оставшиеся случаи намеренно получают одно и то же действие.

Если интересует один вариант

if let соединяет условную ветку из урока 12 с одним образцом. if let Status::Doing(minutes) = status не присваивает новое значение status и не сравнивает два числа: запись спрашивает, подходит ли форма значения образцу, а при успехе даёт числу имя minutes. else обрабатывает прочие варианты. Это отдельная программа; её результат не зависит от предыдущего примера.

enum Status { Planned, Doing(u32), Done }

fn main() {
    let status = Status::Doing(5);
    if let Status::Doing(minutes) = status {
        println!("Идёт работа: {minutes} мин");
    } else {
        println!("Сейчас работа не идёт");
    }
}
Идёт работа: 5 мин

Когда у всех вариантов разные действия, выбирайте полный match. Когда важен только один вариант, if let сокращает запись; ветка else нужна, если остальные случаи тоже требуют действия.

Контрольная точка 26–30

Объясните без страницы: кортеж собирает места по порядку; структура даёт местам имена; метод связывает действие с типом; перечисление ограничивает варианты; match проверяет их полный разбор. Если один шаг пропал, вернитесь к соответствующему уроку 26–29 и восстановите его опорную карту.

Задание

Обязательное. Создайте Status с Planned, Doing(u32) и Done. Сделайте функцию active_minutes(status: Status) -> u32 с полным match: 0 для Planned и Done, внутреннее число для Doing. В main вызовите её для Doing(25) и Done; выведите Работа: 25 мин и После завершения: 0 мин. Не заменяйте match готовыми числами в println!.

Граница. Уберите ветку Done, прочитайте E0004 и верните её.

Подсказка

Сделайте match status последним выражением функции без ;. Ветке Status::Doing(minutes) достаточно вернуть minutes.

Эталон после попытки

enum Status {
    Planned,
    Doing(u32),
    Done,
}

fn active_minutes(status: Status) -> u32 {
    match status {
        Status::Planned => 0,
        Status::Doing(minutes) => minutes,
        Status::Done => 0,
    }
}

fn main() {
    let during = active_minutes(Status::Doing(25));
    let after = active_minutes(Status::Done);
    println!("Работа: {during} мин");
    println!("После завершения: {after} мин");
}
Работа: 25 мин
После завершения: 0 мин

Теперь функция даёт определённый результат для каждого состояния. Официальный разбор match и if let.

Предыдущий урок · Оглавление · Следующий урок

Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом

Комментарии (0)

Пока нет комментариев. Будьте первым.