2015-09-24 4 views
5

In Rust, tendo ad avere problemi di progettazione quando si tratta di scrivere moduli con caratteristiche. Io non sono sempre sicuro se voglio:Quali sono le differenze tra un metodo Trait predefinito e una funzione parametrizzata?

pub trait Foo { 
    fn foo(&self) -> bool; 

    fn bar(&self) { 
     if self.foo() { 
      // Do something! 
     } else { 
      // Do something else! 
     } 
    } 
} 

O

pub trait Foo { 
    fn foo(&self) -> bool; 
} 

pub fn bar<T>(fooer: &T) where T: Foo { 
    if fooer.foo() { 
     // Do something! 
    } else { 
     // Do something else! 
    } 
} 

(Naturalmente, esempi reali sono suscettibili di avere tratti più elaborati o firme funzione)

Mentre temi del design sono oltre lo scopo di Stack Overflow, non sono del tutto sicuro di aver compreso le differenze significative e oggettive tra i due, e non ho voglia di sfogliare la libreria standard ha fatto molta luce. È sembra come la libreria standard di Rust preferisce utilizzare variable.method() in contrasto con mod::function(&variable) nella maggior parte dei casi. Tuttavia, questo non risponde ancora alla domanda poiché si tratta solo di una guida alla guida allo stile piuttosto che basarsi su una conoscenza oggettiva della differenza.

Oltre all'evidente differenza sintattica, quali sono le principali differenze funzionali tra un metodo di tratto predefinito e una funzione parametrizzata a livello di modulo? Una grande domanda che ho è: il metodo di tratto predefinito monomorfizza per utilizzare la distribuzione statica o lo fa se prende lo self come se fosse un oggetto tratto?

L'unica differenza che mi viene in mente è che un impl del tratto può scegliere di ignorare l'implementazione del metodo predefinito, si spera/presumibilmente fornendo un'implementazione che soddisfi lo stesso contratto, mentre sono garantito che l'implementazione mod::function esegue sempre lo stesso identico codice, indipendentemente da cosa (nel bene o nel male). C'è niente altro? La risposta cambia se sono coinvolti tipi associati o tratti di estensione?

risposta

4

In realtà hai risposto alla domanda tu stesso, congratulazioni!

Poiché Rust ha solo il principio di sovraccarico/override tramite tratti, la differenza semantica essenziale è che un tratto method può essere sostituito, e quindi personalizzato, mentre una funzione libera non può.

Tecnicamente, sia Trait::func(&self) sia mod::func<T: Trait>(&T) vengono monoformati mentre mod::func(&Trait) non è (e quindi si verificherà il leggero sovraccarico delle chiamate virtuali).

Inoltre, vi è un lieve sovraccarico di memoria su Trait::func(&self): un'ultima voce nella tabella virtuale. È probabilmente impercettibile.

In fine, la scelta è generalmente un giudizio. Che tu apra la porta alla personalizzazione o meno, è la tua scelta.

Problemi correlati