Typy wyliczeniowe z danymi
Część sekcji Programowanie obiektowe ścieżki Rust w Coddy. Lekcja 14 z 61.
Podstawowe wyliczenia w Rust pozwalają zdefiniować typ o stałym zestawie wariantów, takich jak Direction::North lub Status::Active. Wyliczenia w Rust są jednak znacznie potężniejsze. Każdy wariant może przechowywać własne dane, dzięki czemu wyliczenia są niezwykle elastyczne w modelowaniu rzeczywistych scenariuszy.
Wyobraź sobie system przesyłania wiadomości, w którym różne typy wiadomości zawierają różne informacje. Wiadomość tekstowa ma treść, polecenie ruchu ma współrzędne, a sygnał zakończenia nie zawiera niczego. W Rust możesz przedstawić je wszystkie za pomocą jednego typu wyliczeniowego:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(u8, u8, u8),
}
Każdy wariant ma inny kształt. Quit nie przechowuje żadnych danych: to tylko sygnał.
Move używa składni podobnej do struktury z nazwanymi polami. Write przechowuje pojedynczy String przy użyciu składni krotki. ChangeColor przechowuje trzy wartości reprezentujące składowe RGB.
Tworzenie instancji tych wariantów wygląda tak:
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);
Zaletą tego podejścia jest to, że m1, m2, m3 i m4 mają ten sam typ: Message. Możesz przechowywać je w tej samej kolekcji, przekazywać do tej samej funkcji lub zwracać dowolny wariant z jednej funkcji. Enum łączy różne kształty danych w jeden typ, zachowując przy tym konkretne informacje potrzebne każdemu wariantowi.
Wyzwanie
ŁatwyZbudujmy system powiadomień, który używa wyliczeń z danymi do reprezentowania różnych typów alertów. Każdy typ powiadomienia zawiera inne informacje: niektóre mają wiadomości, niektóre wartości liczbowe, a niektóre są prostymi sygnałami.
Utworzysz dwa pliki, aby uporządkować kod:
notification.rs: Zdefiniuj publiczne wyliczenieNotificationz trzema wariantami:Alert: przechowuje pojedynczą wiadomość typuString(składnia krotkowa)Reminder: przechowuje nazwane pola:title(String) iminutes(u32)Dismiss: nie przechowuje żadnych danych, jest tylko sygnałem
main.rs: Dołącz moduł powiadomień i utwórz po jednej instancji każdego wariantu. Następnie wyświetl informacje o każdym powiadomieniu, aby pokazać, że wszystkie trzy warianty są tego samego typu, ale zawierają różne dane.
Do wyświetlania użyj formatowania debug ({:?}), aby pokazać każde powiadomienie. Musisz zaimplementować cechę Debug w swoim wyliczeniu, aby można je było wyświetlać w ten sposób.
Wynik powinien pokazywać wszystkie trzy powiadomienia, każde w osobnym wierszu:
Alert("{message}")
Reminder { title: "{title}", minutes: {minutes} }
DismissNa przykład dla wiadomości alertu "Server down", przypomnienia o tytule "Meeting" i 30 minut wynik wyglądałby tak:
Alert("Server down")
Reminder { title: "Meeting", minutes: 30 }
DismissOtrzymasz trzy dane wejściowe: wiadomość alertu, tytuł przypomnienia oraz liczbę minut przypomnienia.
Spróbuj swoich sił
mod notification;
use notification::Notification;
fn main() {
// Wczytaj dane wejściowe
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: Utwórz powiadomienie Alert, używając alert_message
// TODO: Utwórz powiadomienie Reminder, używając reminder_title i reminder_minutes
// TODO: Utwórz powiadomienie Dismiss
// TODO: Wypisz każde powiadomienie, używając formatowania debugowania {:?}
// Każde powiadomienie powinno zostać wypisane w osobnym wierszu
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Metody i zachowanie
Wprowadzenie do bloków implementacjiParametr selfMetody modyfikująceFunkcje powiązaneWiele bloków implementacjiŁańcuchowe wywoływanie metodPowtórzenie — działania na prostokącie4Projekt: Wirtualne zwierzątko
Definiowanie zwierzątkaKarmienie zwierzątka7Standardowe cechy
Cecha DebugCecha DisplayClone i CopyCechy równościPowtórka – punkt do wydrukowania10Projekt: System dokumentów
Trait DrawKomponent tekstowy2Hermetyzacja i moduły
Podstawy modułówSłowo kluczowe publicPola prywatneGetterySetteryPodsumowanie — bezpieczna skrytka5Typy generyczne
Struktury generyczneMetody generyczneWiele typów generycznychFunkcje generycznePodsumowanie – punkt współrzędnych8Cechy jako ograniczenia
Składnia ograniczeń cechWiele ograniczeńKlauzula whereZwracanie typów z użyciem cechPodsumowanie — generyczna drukarka11Wzorce projektowe w Rust
Wzorzec NewtypeKompozycjaTrait DropFrom i IntoPodsumowanie — atrapowy inteligentny wskaźnik3Zaawansowane typy wyliczeniowe
Typy wyliczeniowe z danymiMetody typów wyliczeniowychDopasowywanie wariantów danychTyp wyliczeniowy Option — powtórzeniePodsumowanie — typ wyliczeniowy Shape6Definiowanie cech
Czym jest cecha?Implementowanie cechImplementacje domyślneNadpisywanie wartości domyślnychCechy z parametramiPowtórzenie — odtwarzacz multimedialnyPoćwicz samodzielnie: Kompilator Rust online