Geschiedenis van de vraag
Rust leent het concept van methoden van objectgeoriënteerde talen, maar implementeert ze anders: in plaats van de gebruikelijke this of self, accepteren methoden expliciet een self-parameter. Geassocieerde functies zijn ontstaan als een alternatief voor statische methoden in andere programmeertalen - ze zijn verbonden met het type, maar niet met een specifieke waarde.
Probleem
Mensen verwarren vaak methoden, geassocieerde functies en vrije functies. Het is niet altijd duidelijk wanneer je een methode met self moet gebruiken en wanneer een geassocieerde functie zonder self. Er zijn kwesties van zichtbaarheid, autodereferentie, eigendomsoverdracht.
Oplossing
Methoden in Rust worden gedeclareerd met de eerste parameter als self/ &self/ &mut self binnen een impl-blok (meestal voor struct of enum). Ze worden aangeroepen op een instantie: object.method(). Geassocieerde functies (bijvoorbeeld new, from) worden ook binnen impl gedeclareerd, maar zonder de eerste parameter self en worden aangeroepen via dubbele dubbelepunten: Type::function().
Voorbeeldcode:
struct Point { x: f64, y: f64, } impl Point { // Geassocieerde functie (constructor) fn new(x: f64, y: f64) -> Self { Self { x, y } } // Methode: vereist self fn distance_from_origin(&self) -> f64 { (self.x.powi(2) + self.y.powi(2)).sqrt() } } let p = Point::new(3.0, 4.0); printf!("{}", p.distance_from_origin()); // 5.0
Belangrijkste kenmerken:
::Kan je geassocieerde functies aanroepen via een instantie (via een punt)?
Dit is mogelijk (bijvoorbeeld p.new(1.0, 2.0)), maar sterk onaanbevolen: dit leidt tot verwarring, omdat de geassocieerde functie geen toegang heeft tot het huidige object, en de instantie wordt ignorend doorgegeven. Het is beter om de syntaxis Type::func() te gebruiken.
Voorbeeldcode:
let p = Point::new(1.0, 2.0); let q = p.new(0.0, 0.0); // Werkt, maar is geen best practice!
Kunnen methoden asynchroon zijn?
Ja. Methodes kunnen worden gedeclareerd met het sleutelwoord async, net als vrije functies:
impl Foo { async fn do_async(&self) { // ... } }
Kun je binnen één impl-blok zowel methoden als geassocieerde functies declareren?
Ja - alle combinaties zijn toegestaan. Het is ook mogelijk om meerdere impl-blokken voor één type te declareren.
Een beginner heeft de functie new buiten impl gedeclareerd en probeerde deze als constructor te gebruiken, en riep deze vervolgens per ongeluk via een instantie aan: p.new(1.0, 2.0).
Voordelen:
Werkt snel (compiler staat het toe).
Nadelen:
Code is moeilijk leesbaar, moeilijk te onderhouden, moeilijk om methoden met de juiste eigendom van self te gebruiken.
Alle methoden en geassocieerde functies zijn strikt binnen impl gedeclareerd, de juiste aanroep-syntaxis is gebruikt (Type::new() voor constructeurs, obj.method() voor acties).
Voordelen:
Hoge leesbaarheid, voldoet aan best practices.
Nadelen:
Vereist kennis van Rust-idiomen en aandacht voor syntaxis.