Trait-objekt och dyn
Dynamisk dispatch
Trait-objekt och dyn är en gratis lektion i Lär dig programmera i Rust på CoddyKit. Detta är lektion 2 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Lär dig programmera i Rust, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Lär dig programmera i Rust innehåller totalt 4 lektioner.
Problemet: blandade typer
Generiska typer med trait bounds fungerar utmärkt när varje anrop använder en konkret typ. Men vad händer om ni vill ha en samling av olika typer som alla delar ett trait? Generiska typer kan inte innehålla en blandning.
Trait-objekt löser detta.
Vad är ett trait-objekt?
Ett trait-objekt är ett värde som refereras till via en pekare tillsammans med nyckelordet dyn, till exempel &dyn Trait eller Box<dyn Trait>.
Det gör att ni kan behandla många konkreta typer enhetligt vid körning.
En Box med dyn Trait
Box<dyn Trait> äger ett heapvärde av någon typ som implementerar traitet. Ni kan anropa traitets metoder utan att känna till den konkreta typen.
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());
}En Vec med trait-objekt
Den stora fördelen är att en enda vektor kan innehålla många olika typer, så länge varje typ implementerar traitet.
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());
}
}Dynamisk dispatch
Med traitobjekt väljs metoden som ska anropas vid körning genom att den slås upp i en dold tabell (vtabellen). Detta kallas dynamisk dispatch.
Kostnaden är en liten indirektion; fördelen är flexibilitet vid körning.
Funktioner som returnerar traitobjekt
En funktion kan returnera Box<dyn Trait> när den konkreta typen varierar. Detta är användbart för fabriksfunktioner som avgör typen vid körning.
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());
}Lånade traitobjekt
Ni kan också skicka med ett lånat traitobjekt med &dyn Trait när ni inte behöver ägarskap. Ingen heapallokering sker.
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);
}Objektsäkerhet
Alla traits kan inte användas som traitobjekt. En trait måste vara objektsäker: i grova drag får dess metoder inte returnera Self som värde eller använda generiska typparametrar.
Metoder som tar &self och använder konkreta typer går bra.
Ett exempel som inte är objektsäkert
En trait med en metod som returnerar Self kan inte användas som dyn, eftersom storleken på Self är okänd bakom en pekare. Håll traits som ska användas som traitobjekt enkla.
Ett pluginliknande exempel
Traitobjekt passar utmärkt för pluginsystem: lagra en lista med hanterare bakom dyn och kör dem alla utan att bry er om de konkreta typerna.
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);
}När ni bör använda dyn
Använd traitobjekt när ni behöver heterogena samlingar, typer som väljs vid körning eller vill minska koduppblåsningen från många generiska instansieringar.
Annars bör ni föredra generics för maximal hastighet.
Snabb kontroll
Testa hur väl ni förstår traitobjekt.
Sammanfattning
Ni har lärt er dynamisk dispatch:
- Traitobjekt använder
dynbakom en pekare (Box<dyn T>,&dyn T) - De möjliggör heterogena samlingar och typer som väljs vid körning
- Metodanrop går via en vtabell (dynamisk dispatch)
- Traits måste vara objektsäkra för att kunna användas på detta sätt
Lär dig Rust med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 39
- Lektioner
- 144
Vanliga frågor
Är lektionen ”Trait-objekt och dyn” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Lär dig programmera i Rust, inklusive ”Trait-objekt och dyn”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Lär dig programmera i Rust innehåller totalt 4 lektioner.
Vad lär jag mig i ”Trait-objekt och dyn”?
Dynamisk dispatch Ni övar på Lär dig programmera i Rust med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Lär dig programmera i Rust?
Du behöver inga förkunskaper. Utbildningen i Lär dig programmera i Rust på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.
Hur lång tid tar lektionen ”Trait-objekt och dyn”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Lär dig programmera i Rust-lektionen?
Ja. Varje Lär dig programmera i Rust-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Definiera traits
- Trait-objekt och dyn
- Statisk jämfört med dynamisk dispatch
- Standardmetoder