Menu
Coddy logo textTech

Vettori di trait

Fa parte della sezione Programmazione orientata agli oggetti del percorso Rust di Coddy. Lezione 46 di 61.

Hai visto come Box<dyn Trait> permette a una singola variabile di contenere tipi diversi. La vera potenza emerge quando lo combini con le collezioni: memorizzare più tipi diversi in un singolo vettore.

Un vettore regolare richiede che tutti gli elementi siano dello stesso tipo. Non puoi avere un Vec<Dog> che contenga anche dei gatti. Ma con gli oggetti trait puoi creare un vettore che contiene qualsiasi cosa implementi un trait condiviso:

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),
    ];
}

Il tipo Vec<Box<dyn Speak>> significa «un vettore di oggetti trait allocati in box». Ogni elemento è un Box che punta a qualcosa che implementa Speak: i tipi effettivi possono essere diversi. Avvolgi ogni valore con Box::new() quando lo aggiungi al vettore.

Questo schema è essenziale per creare sistemi flessibili in cui devi gestire raccolte di oggetti correlati ma diversi, come componenti dell'interfaccia utente, entità di gioco o sistemi di plugin.

challenge icon

Sfida

Facile

Costruiamo un sistema di notifiche in grado di gestire diversi tipi di avvisi! Creerai una raccolta che memorizza vari tipi di notifiche: email, messaggi SMS e notifiche push, tutte in un unico vettore usando oggetti trait.

Organizzerai il codice in due file:

  • notifications.rs: definisci un trait pubblico Notify con un metodo send che accetta &self e restituisce una String che descrive la notifica inviata. Poi crea tre struct pubbliche:
    • Email: con un campo pubblico recipient (String). Il suo metodo send dovrebbe restituire Email to: {recipient}
    • Sms: con un campo pubblico phone (String). Il suo metodo send dovrebbe restituire SMS to: {phone}
    • Push: con un campo pubblico device (String). Il suo metodo send dovrebbe restituire Push to: {device}
  • main.rs: importa il modulo notifications e crea un vettore di tipo Vec<Box<dyn Notify>> che contenga tutti e tre i tipi di notifica. Usa gli input forniti per creare una notifica di ciascun tipo, aggiungile al vettore nell'ordine indicato (Email, Sms, Push), quindi stampa il risultato della chiamata a send() sul primo elemento del vettore.

Il concetto chiave è che, nonostante Email, Sms e Push siano struct completamente diverse, possono convivere tutte nello stesso vettore perché condividono il trait Notify. Ogni elemento viene racchiuso con Box::new() per creare l'oggetto trait.

L'output dovrebbe mostrare la prima notifica:

Email to: {recipient}

Per esempio, con gli input alice@example.com, 555-1234 e iPhone-12:

Email to: alice@example.com

Riceverai tre input: il destinatario dell'email, il numero di telefono e il nome del dispositivo.

Provalo tu

mod notifications;

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

fn main() {
    // Leggi gli input
    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: Crea un Vec<Box<dyn Notify>> per contenere diversi tipi di notifiche
    // TODO: Crea istanze di Email, Sms e Push usando gli input
    // TODO: Aggiungile al vettore nell'ordine (Email, Sms, Push) usando Box::new()
    // TODO: Stampa il risultato della chiamata a send() sul primo elemento
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Rust online