Menu
Coddy logo textTech

Wektory obiektów cech

Część sekcji Programowanie obiektowe ścieżki Rust w Coddy. Lekcja 46 z 61.

Widzisz już, jak Box<dyn Trait> pozwala jednej zmiennej przechowywać różne typy. Prawdziwa moc ujawnia się, gdy połączysz to z kolekcjami: przechowywaniem wielu różnych typów w jednej tablicy.

Zwykła tablica wymaga, aby wszystkie elementy były tego samego typu. Nie możesz mieć Vec<Dog>, który zawiera również koty. Jednak dzięki obiektom cech możesz utworzyć tablicę, która przechowuje wszystko, co implementuje wspólną cechę:

trait Speak {
    fn speak(&self) -> String;
}

struct Dog;
struct Cat;
struct Bird;

impl Speak for Dog {
    fn speak(&self) -> String { String::from("Woof!") }
}

impl Speak for Cat {
    fn speak(&self) -> String { String::from("Meow!") }
}

impl Speak for Bird {
    fn speak(&self) -> String { String::from("Tweet!") }
}

fn main() {
    let animals: Vec<Box<dyn Speak>> = vec![
        Box::new(Dog),
        Box::new(Cat),
        Box::new(Bird),
    ];
}

Typ Vec<Box<dyn Speak>> oznacza „wektor obiektów cech opakowanych w pudełka”. Każdy element to Box wskazujący na coś, co implementuje Speak: rzeczywiste typy mogą się różnić. Każdą wartość opakowujesz za pomocą Box::new(), dodając ją do wektora.

Ten wzorzec jest niezbędny do tworzenia elastycznych systemów, w których trzeba zarządzać kolekcjami powiązanych, ale różnych obiektów, takich jak komponenty interfejsu użytkownika, obiekty w grze lub systemy wtyczek.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system powiadomień, który obsługuje różne typy alertów! Utworzysz kolekcję przechowującą różne typy powiadomień — e-maile, wiadomości SMS i powiadomienia push — wszystkie w jednym wektorze z użyciem obiektów cech.

Rozmieścisz swój kod w dwóch plikach:

  • notifications.rs: Zdefiniuj publiczną cechę Notify z metodą send, która przyjmuje &self i zwraca wartość typu String opisującą wysyłane powiadomienie. Następnie utwórz trzy publiczne struktury:
    • Email: z publicznym polem recipient (String). Metoda send powinna zwracać Email to: {recipient}
    • Sms: z publicznym polem phone (String). Metoda send powinna zwracać SMS to: {phone}
    • Push: z publicznym polem device (String). Metoda send powinna zwracać Push to: {device}
  • main.rs: Dołącz moduł powiadomień i utwórz wektor typu Vec<Box<dyn Notify>>, który przechowuje wszystkie trzy typy powiadomień. Użyj podanych danych wejściowych, aby utworzyć po jednym powiadomieniu każdego typu, dodaj je do wektora w tej kolejności (Email, Sms, Push), a następnie wypisz wynik wywołania send() dla pierwszego elementu wektora.

Kluczowe jest to, że mimo iż Email, Sms i Push to zupełnie różne struktury, mogą znajdować się razem w tym samym wektorze, ponieważ współdzielą cechę Notify. Każdy element jest opakowywany za pomocą Box::new(), aby utworzyć obiekt cechy.

Wynik powinien pokazywać pierwsze powiadomienie:

Email to: {recipient}

Na przykład dla danych wejściowych alice@example.com, 555-1234 i iPhone-12:

Email to: alice@example.com

Otrzymasz trzy dane wejściowe: adres e-mail odbiorcy, numer telefonu i nazwę urządzenia.

Spróbuj swoich sił

mod notifications;

use notifications::{Notify, Email, Sms, Push};

fn main() {
    // Wczytaj dane wejściowe
    let mut recipient = String::new();
    std::io::stdin().read_line(&mut recipient).expect("Failed to read line");
    let recipient = recipient.trim().to_string();

    let mut phone = String::new();
    std::io::stdin().read_line(&mut phone).expect("Failed to read line");
    let phone = phone.trim().to_string();

    let mut device = String::new();
    std::io::stdin().read_line(&mut device).expect("Failed to read line");
    let device = device.trim().to_string();

    // TODO: Utwórz Vec<Box<dyn Notify>> do przechowywania różnych typów powiadomień
    // TODO: Utwórz instancje Email, Sms i Push, używając danych wejściowych
    // TODO: Dodaj je do wektora w kolejności (Email, Sms, Push), używając Box::new()
    // TODO: Wypisz wynik wywołania send() na pierwszym elemencie
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Rust online