Dispatching is een mechanisme voor het kiezen van specifieke functies (methoden) om aan te roepen. In Rust zijn er twee benaderingen: statische en dynamische dispatch.
Achtergrond:
In OOP-talen wordt meestal een vtable (virtuele tabel) gebruikt voor dynamische methodaanroepen. In Rust is er een vergelijkbare implementatie voor trait objects — verwijzingen naar objecten van typen die bepaalde traits implementeren. Statische dispatch komt naar voren bij het gebruik van generics en trait bounds.
Probleem:
Vaak moet men kiezen tussen flexibiliteit (de mogelijkheid om met objecten van verschillende typen via één interface te werken) en prestaties (statische dispatch maakt het mogelijk om methoden in te lijnen). Onjuiste keuzes leiden tot ofwel onnodig complexe generics of tot prestatieverlies.
Oplossing:
Statische dispatch wordt bereikt via generieke parameters: de compiler genereert afzonderlijke code voor elk type. Dynamische dispatch gebeurt wanneer een functie een argument van het type &dyn Trait of Box<dyn Trait> accepteert; bij het aanroepen van een methode via een trait kijkt Rust in de vtable op het adres, zoals in klassieke OOP-talen.
Voorbeeldcode:
trait Shape { fn area(&self) -> f64; } impl Shape for Circle { fn area(&self) -> f64 { 3.1415 * self.radius * self.radius } } fn print_area(shape: &dyn Shape) { // dynamische dispatch println!("area = {}", shape.area()); } // Of statisch: fn print_area_static<S: Shape>(shape: &S) { println!("area = {}", shape.area()); }
Belangrijke kenmerken:
dyn Trait maakt gebruik van de vtable (dynamische dispatch)Is het mogelijk om Box<dyn Sized> te maken?
Nee. dyn Trait is per definitie unsized en vereist altijd het gebruik van Box, Arc of referenties, maar niet "Box<dyn Sized>" — dat heeft geen zin. Trait objects hebben geen Sized trait.
Is dyn Trait toegestaan voor traits met generieke methoden?
Nee. Je kunt geen object-safe traits maken met generieke methoden (dat wordt vaak verward!), samengestelde typen zijn niet object-safe:
trait MyTrait { fn foo<T>(&self, x: T); } let x: &dyn MyTrait = ... // Compilatiefout!
Is het mogelijk om dyn Trait te maken voor een trait met Self-waarden in de handtekening?
Dat kan niet, als de methode Self retourneert (veel mensen begrijpen deze nuance niet: object safety vereist dat er geen Self in de handtekening is; self kan alleen in de argumenten, maar niet in de geretourneerde waarde).
Overal werd dyn Trait gebruikt voor de veelzijdigheid van interfaces, zelfs binnen strakke lussen, waar generics gebruikt hadden kunnen worden.
Voordelen:
Nadelen:
Statische dispatch werd toegepast in de interne logica, en dyn Trait alleen aan de grenzen van modules.
Voordelen:
Nadelen: