Перечисления с данными
Часть раздела Объектно-ориентированное программирование путешествия по Rust на Coddy. Урок 14 из 61.
Базовые перечисления в Rust позволяют определить тип с фиксированным набором вариантов, например Direction::North или Status::Active. Но перечисления Rust гораздо мощнее. Каждый вариант может содержать собственные данные, что делает перечисления невероятно гибкими для моделирования сценариев из реального мира.
Рассмотрим систему обмена сообщениями, в которой разные типы сообщений содержат разную информацию. Текстовое сообщение содержит содержимое, команда Move — координаты, а сигнал завершения не содержит вообще ничего. В Rust можно представить всё это с помощью одного перечисления:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(u8, u8, u8),
}
Each вариант имеет различную форму. Quit не содержит данных: это всего лишь сигнал.
Move использует синтаксис, похожий на синтаксис структур, с полями named. Write содержит единственное значение String, используя синтаксис кортежей. ChangeColor содержит три значения, представляющие компоненты RGB.
Создание экземпляров этих вариантов выглядит так:
let m1 = Message::Quit;
let m2 = Message::Move { x: 10, y: 20 };
let m3 = Message::Write(String::from("Hello"));
let m4 = Message::ChangeColor(255, 128, 0);
Преимущество этого подхода в том, что m1, m2, m3 и m4 имеют один и тот же тип: Message. Ты можешь хранить их в одной коллекции, передавать их одной и той же функции или возвращать любой вариант из одной функции. Перечисление объединяет различные формы данных под одним типом, сохраняя при этом конкретную информацию, необходимую каждому варианту.
Задание
ЛегкоДавайте создадим систему уведомлений, которая использует enum с данными для представления разных типов оповещений. Каждый тип уведомления содержит разную информацию: некоторые содержат сообщения, некоторые — числовые значения, а некоторые являются простыми сигналами.
Вы создадите два файла, чтобы организовать свой код:
notification.rs: Define общедоступный enumNotificationс тремя вариантами:Alert: holds одно значениеStringmessage (синтаксис кортежа)Reminder: holds именованные поля:title(String) иminutes(u32)Dismiss: holds no data, только сигнал
main.rs: Подключите модуль notification и создайте по одному экземпляру каждого варианта. Затем выведите информацию о каждом уведомлении, чтобы продемонстрировать, что все три варианта имеют один и тот же тип, но содержат разные данные.
При выводе используйте отладочное форматирование ({:?}), чтобы отобразить каждое уведомление. Вам потребуется вывести для вашего enum производный трейт Debug, чтобы его можно было печатать таким образом.
Ваш вывод должен содержать все три уведомления, каждое на своей строке:
Alert("{message}")
Reminder { title: "{title}", minutes: {minutes} }
DismissНапример, если значение alert message — "Server down", title напоминания — "Meeting", а значение 30 — это количество minutes, вывод будет таким:
Alert("Server down")
Reminder { title: "Meeting", minutes: 30 }
DismissВы получите три входных значения: alert message, title напоминания и значение reminder minutes.
Попробуйте сами
mod notification;
use notification::Notification;
fn main() {
// Читаем входные данные
let mut alert_message = String::new();
std::io::stdin().read_line(&mut alert_message).expect("Failed to read line");
let alert_message = alert_message.trim().to_string();
let mut reminder_title = String::new();
std::io::stdin().read_line(&mut reminder_title).expect("Failed to read line");
let reminder_title = reminder_title.trim().to_string();
let mut minutes_input = String::new();
std::io::stdin().read_line(&mut minutes_input).expect("Failed to read line");
let reminder_minutes: u32 = minutes_input.trim().parse().expect("Failed to parse minutes");
// TODO: Создать уведомление Alert, используя alert_message
// TODO: Create a Reminder notification using reminder_title and reminder_minutes
// TODO: Создать уведомление Dismiss
// TODO: Вывести каждое уведомление, используя отладочное форматирование {:?}
// Каждое уведомление должно быть выведено на своей строке
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Методы и поведение
Введение в блоки реализацииПараметр SelfИзменяемые методыАссоциированные функцииНесколько блоков реализацииЦепочки вызовов методовИтоги: действия с Rectangle4Проект: Виртуальный питомец
Определение питомцаКормление питомца2Инкапсуляция и модули
Основы модулейКлючевое слово PublicПриватные поляГеттерыСеттерыИтоги — Безопасный сейф5Обобщения
Обобщённые структурыОбобщённые методыНесколько обобщённых типовОбобщённые функцииПовторение — Координатная точка8Трейты как ограничения
Синтаксис ограничений трейтовМножественные ограниченияКонструкция whereВозврат типов с трейтамиИтоги — Обобщённый принтер11Паттерны проектирования в Rust
Паттерн NewtypeКомпозицияТрейт DropFrom и IntoИтоги — Мок-объект Smart Pointer3Продвинутые перечисления
Перечисления с даннымиМетоды в перечисленияхСопоставление вариантов с даннымиСнова об Option EnumИтоги — перечисление Shape6Определение трейтов
Что такое трейт?Реализация трейтовРеализации по умолчаниюПереопределение реализаций по умолчаниюТрейты с параметрамиИтоги — Media PlayerПотренируйтесь самостоятельно: Онлайн-компилятор Rust