0Pricing
Learn Rust Coding · Lezione

Trait object e dyn

Dispatch dinamico

Trait object e dyn è una lezione Learn Rust Coding gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Learn Rust Coding, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Learn Rust Coding include 4 lezioni in totale.

Il problema: tipi misti

I generics con vincoli di trait funzionano molto bene quando ogni chiamata utilizza un unico tipo concreto. Ma cosa succede se desidera una collezione di tipi diversi che condividono tutti un trait? I generics non possono contenere tipi misti.

Gli oggetti trait risolvono questo problema.

Che cos'è un oggetto trait?

Un oggetto trait è un valore a cui si fa riferimento tramite un puntatore e la parola chiave dyn, come &dyn Trait o Box<dyn Trait>.

Permette di trattare in modo uniforme, a runtime, molti tipi concreti.

Un Box di dyn Trait

Box<dyn Trait> possiede un valore nell'heap di un tipo che implementa il trait. Può chiamare i metodi del trait senza conoscere il tipo concreto.

trait Speak { fn say(&self) -> String; }
struct Dog;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }

fn main() {
    let animal: Box<dyn Speak> = Box::new(Dog);
    println!("{}", animal.say());
}

Un Vec di oggetti trait

Il vantaggio principale è che un singolo vettore può contenere molti tipi diversi, purché ciascuno implementi il trait.

trait Speak { fn say(&self) -> String; }
struct Dog;
struct Cat;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }
impl Speak for Cat { fn say(&self) -> String { String::from("Meow") } }

fn main() {
    let zoo: Vec<Box<dyn Speak>> = vec![Box::new(Dog), Box::new(Cat)];
    for animal in &zoo {
        println!("{}", animal.say());
    }
}

Dispatch dinamico

Con gli oggetti trait, il metodo da chiamare viene scelto a runtime cercandolo in una tabella nascosta (la vtable). Questo meccanismo è chiamato dispatch dinamico.

Il costo è una piccola indirezione; il vantaggio è la flessibilità a runtime.

Funzioni che restituiscono oggetti trait

Una funzione può restituire Box<dyn Trait> quando il tipo concreto varia. È utile per le factory function che decidono il tipo a runtime.

trait Speak { fn say(&self) -> String; }
struct Dog;
struct Cat;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }
impl Speak for Cat { fn say(&self) -> String { String::from("Meow") } }

fn make(kind: &str) -> Box<dyn Speak> {
    if kind == "dog" { Box::new(Dog) } else { Box::new(Cat) }
}

fn main() {
    println!("{}", make("cat").say());
}

Oggetti trait presi in prestito

Può anche passare un oggetto trait preso in prestito con &dyn Trait quando non ha bisogno di trasferirne la proprietà. Non viene effettuata alcuna allocazione nell'heap.

trait Speak { fn say(&self) -> String; }
struct Dog;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }

fn announce(s: &dyn Speak) {
    println!("heard: {}", s.say());
}

fn main() {
    let d = Dog;
    announce(&d);
}

Sicurezza per gli oggetti

Non tutti i trait possono essere utilizzati come oggetti trait. Un trait deve essere object safe: in linea di massima, i suoi metodi non possono restituire Self per valore né utilizzare parametri di tipo generici.

I metodi che accettano &self e utilizzano tipi concreti sono validi.

Un esempio non compatibile con gli oggetti

Un trait con un metodo che restituisce Self non può essere utilizzato come dyn, perché la dimensione di Self è sconosciuta dietro un puntatore. Mantenga semplici i trait utilizzati come oggetti.

Un esempio in stile plugin

Gli oggetti trait sono ideali per i sistemi di plugin: memorizzi un elenco di gestori dietro dyn ed esegua tutti i gestori senza preoccuparsi dei tipi concreti.

trait Task { fn run(&self) -> i32; }
struct Add { a: i32, b: i32 }
struct Negate { x: i32 }
impl Task for Add { fn run(&self) -> i32 { self.a + self.b } }
impl Task for Negate { fn run(&self) -> i32 { -self.x } }

fn main() {
    let tasks: Vec<Box<dyn Task>> = vec![Box::new(Add { a: 2, b: 3 }), Box::new(Negate { x: 7 })];
    let total: i32 = tasks.iter().map(|t| t.run()).sum();
    println!("total {}", total);
}

Quando scegliere dyn

Utilizzi gli oggetti trait quando ha bisogno di collezioni eterogenee, di tipi scelti a runtime o di ridurre l'aumento delle dimensioni del codice dovuto a molte istanziazioni generiche.

In caso contrario, preferisca i generics per ottenere la massima velocità.

Verifica rapida

Verifichi la Sua comprensione degli oggetti trait.

Riepilogo

Ha imparato il dispatch dinamico:

  • Gli oggetti trait utilizzano dyn dietro un puntatore (Box<dyn T>, &dyn T)
  • Permettono di creare collezioni eterogenee e utilizzare tipi scelti a runtime
  • Le chiamate ai metodi passano attraverso una vtable (dispatch dinamico)
  • I trait devono essere object safe per poter essere utilizzati in questo modo

Domande Frequenti

La lezione «Trait object e dyn» è gratuita?

Sì — il testo completo di «Trait object e dyn» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Learn Rust Coding, passa a CoddyKit PRO. Il corso Learn Rust Coding include 4 lezioni in totale.

Cosa imparerò in «Trait object e dyn»?

Dispatch dinamico Eserciti Learn Rust Coding con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Learn Rust Coding?

Non è richiesta alcuna esperienza precedente. Learn Rust Coding su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «Trait object e dyn»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Learn Rust Coding?

Sì. Ogni lezione Learn Rust Coding include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Definizione dei trait
  2. Trait object e dyn
  3. Dispatch statico e dinamico
  4. Metodi predefiniti
← Torna a Learn Rust Coding