Questo è ora descritto in the second edition of The Rust Programming Language. Tuttavia, tuffiamoci un po 'oltre.
Iniziamo con un esempio più semplice.
Quando è opportuno utilizzare un metodo tratto?
Ci sono diversi modi per fornire tardiva:
trait MyTrait {
fn hello_word(&self) -> String;
}
Oppure:
struct MyTrait<T> {
t: T,
hello_world: fn(&T) -> String,
}
impl<T> MyTrait<T> {
fn new(t: T, hello_world: fn(&T) -> String) -> MyTrait<T>;
fn hello_world(&self) -> String {
(self.hello_world)(self.t)
}
}
prescindere da qualunque strategia di attuazione/prestazioni, entrambi i brani sopra consentono all'utente di specificare in un modalità dinamica come dovrebbe comportarsi hello_world
.
L'unica differenza (semanticamente) è che l'attuazione trait
garantisce che, per un dato tipo T
attuazione del trait
, hello_world
avrà sempre lo stesso comportamento che l'attuazione struct
permette di avere un comportamento differente su una base per esempio.
Se l'utilizzo di un metodo è appropriato o meno dipende dal caso d'uso!
Quando è opportuno utilizzare un tipo associato?
Analogamente ai trait
metodi di cui sopra, un tipo associato è una forma di tardiva (anche se avviene a compilazione), consentendo all'utente di trait
per specificare per una determinata istanza quale tipo di sostituire. Non è l'unico modo (quindi la domanda):
trait MyTrait {
type Return;
fn hello_world(&self) -> Self::Return;
}
Oppure:
trait MyTrait<Return> {
fn hello_world(&Self) -> Return;
}
sono equivalenti alla tardiva dei metodi di cui sopra:
- il primo impone che, per un dato
Self
c'è un singolo Return
associato
- il secondo, invece, consente di implementare
MyTrait
per Self
per multipli Return
Quale forma è più appropriata dipende dal fatto che abbia senso applicare l'unicità o meno. Per esempio:
Deref
utilizza un tipo associato perché senza unicità il compilatore sarebbe impazzito durante l'inferenza
Add
utilizza un tipo associato perché il suo autore pensava che date le due argomenti ci sarebbe una logica tipo di ritorno
Come potete vedere, mentre Deref
è un caso d'uso ovvio (vincolo tecnico), il caso di Add
è meno chiare: forse avrebbe senso per i32 + i32
a cedere sia i32
o Complex<i32>
a seconda del contesto? Ciononostante, l'autore ha esercitato il proprio giudizio e ha deciso che non era necessario sovraccaricare il tipo di ritorno per le aggiunte.
La mia posizione personale è che non c'è una risposta giusta.Tuttavia, al di là dell'argomento dell'unicità, vorrei menzionare che i tipi associati rendono più semplice l'utilizzo della caratteristica in quanto riducono il numero di parametri che devono essere specificati, quindi nel caso in cui i vantaggi della flessibilità dell'uso di un parametro di tratto regolare non siano evidenti, suggerire di iniziare con un tipo associato.
Mi ci è voluto un po 'di tempo per capire. Per me sembra più come definire più tipi contemporaneamente: Edge e Node non hanno senso dal grafico. – tafia