Rust: с нуля до своего органайзера Урок 29 из 40
Перечисление: состояние задачи из допустимых вариантов
Урок 29. Представить состояние задачи одним вариантом, который может хранить дополнительные данные.
Текст переведён с помощью ИИ.
Предварительно: уроки 11, 12, 14 и 27–28. Если поля структуры забылись, повторите урок 27.
Образ и опорная карта
На табличке у двери пишут одно из состояний: «не начато», «в работе», «завершено». Надписи взаимоисключающие. Если хранить три отдельных bool, можно случайно получить «в работе» и «завершено» одновременно. Перечисление (enum) задаёт тип из явно названных вариантов; одно его значение выбирает ровно один вариант. Образ ограничен: некоторые варианты могут хранить дополнительные данные, а простая табличка этого не показывает.
Тип Status → варианты → значение Status::Doing(15) → разбор варианта. enum Status { ... } объявляет возможные состояния. Status::Planned и Status::Done не содержат добавочных данных. Doing(u32) означает: вариант «в работе» хранит одно число минут. Круглые скобки здесь задают тип данных варианта; в Status::Doing(15) они передают конкретное число. :: указывает путь от типа к его варианту. Это не отдельная функция.
Одно состояние за раз
Сохраните прежний src/main.rs проекта organizer, замените файл целиком и выполните cargo run рядом с Cargo.toml. Другие файлы и зависимости не меняются. Предскажите вывод без сообщений Cargo.
Чтобы показать содержимое варианта, нужен способ выбора ветки. match status { ... } сравнивает значение с образцами вариантов. Запись Status::Doing(minutes) => ... означает: если выбран Doing, дать его числу имя minutes и выполнить выражение справа от =>. Знак => отделяет образец от действия; запятая отделяет ветки. Ветки Planned и Done тоже указаны, поэтому каждое допустимое состояние обработано. Подробно потренируем match в следующем уроке.
enum Status {
Planned,
Doing(u32),
Done,
}
fn main() {
let status = Status::Doing(15);
match status {
Status::Planned => println!("Не начато"),
Status::Doing(minutes) => println!("В работе: {minutes} мин"),
Status::Done => println!("Завершено"),
}
}
В работе: 15 мин
Здесь 15 — число уже потраченных минут, а не длительность всей задачи. Вариант Done не может одновременно хранить данные Doing: значение имеет только один вариант. Но Rust не запрещает Doing(0); смысл числа мы должны проверить сами.
Перечисление внутри Task
Поле структуры может иметь наш новый тип. Следующий отдельный пример создаёт задачу, затем меняет только её состояние. Название остаётся тем же.
enum Status {
Planned,
Doing(u32),
Done,
}
struct Task {
title: String,
status: Status,
}
fn main() {
let mut task = Task {
title: String::from("Чтение"),
status: Status::Planned,
};
task.status = Status::Done;
println!("{} завершено", task.title);
}
Чтение завершено
Сообщение после присваивания верно для этого известного пути программы. Для произвольного состояния нужно читать task.status через match, а не печатать готовый вывод. В 30-м уроке сделаем такую проверку.
Данные варианта тоже имеют тип. Этот отдельный пример намеренно не компилируется с E0308: Doing требует u32, а не строку.
enum Status { Doing(u32) }
fn main() {
let status = Status::Doing("15");
}
Проверка понимания
- Почему
Statusлучше трёх независимыхboolдля взаимоисключающих состояний? - Что хранит
Status::Doing(15)кроме имени варианта? - Проверяет ли
enumсам, что число больше нуля?
Проверьте: значение выбирает ровно один вариант; вариант хранит u32 со значением 15; нет, это отдельное правило органайзера. Закройте страницу и восстановите опорную карту.
Задание
Обязательное. Объявите Status с Planned, Doing(u32) и Done. Создайте Status::Doing(25) и через match выведите В работе: 25 мин. Для двух остальных вариантов задайте сообщения Не начато и Завершено, чтобы код подходил для любого состояния. Число в выводе возьмите из варианта.
Изменение. Поменяйте значение на Status::Done и убедитесь, что вывод стал Завершено.
Подсказка
Внутри match status нужны три ветки. В ветке Status::Doing(minutes) имя minutes доступно в println! справа от =>.
Эталон после попытки
enum Status {
Planned,
Doing(u32),
Done,
}
fn main() {
let status = Status::Doing(25);
match status {
Status::Planned => println!("Не начато"),
Status::Doing(minutes) => println!("В работе: {minutes} мин"),
Status::Done => println!("Завершено"),
}
}
В работе: 25 мин
Состояние теперь одно, а данные «в работе» связаны именно с этим вариантом. Официальный разбор перечислений.
Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом
Комментарии (0)
Войдите, чтобы оставить комментарий →
Пока нет комментариев. Будьте первым.