Implementazione di un tratto per più tipi contemporaneamente

Ho due strutture e un tratto:

struct A { x: u32, } struct B { x: u32, } trait T { fn double(&self) -> u32; } 

Vorrei implementare T per entrambe le strutture usando x .

C’è un modo per scrivere qualcosa del genere

 impl T for A, B { fn double(&self) -> u32 { /* ... */ } } 

Mi piacerebbe non usare le macro se ansible.

L’unico modo per implementare una caratteristica una volta per molti tipi concreti è implementare una caratteristica per tutti i tipi che già implementano un’altra caratteristica.

Ad esempio, puoi implementare un tratto marker Xed e poi:

 impl Double for T where T: Xed, { fn double(&self) { /* ... */ } } 

Tuttavia , Rust ha guidato i principi generici. L’unica cosa che sai di T nella precedente implementazione è che T implementa il trait Xed , e quindi gli unici tipi / funzioni associate che puoi usare sono quelli che provengono da Xed .

Un tratto non può esporre un campo / attributo, solo tipi, costanti e funzioni associati, quindi Xed avrebbe bisogno di un getter per x (che non deve essere chiamato x ).

Se si desidera fare affidamento sulle proprietà sintattiche (e non semantiche ) del codice, quindi utilizzare le macro.

La creazione di una macro risolve anche il tuo problema:

 struct A { x: u32, } struct B { x: u32, } trait T { fn double(&self) -> u32; } macro_rules! impl_T { (for $($t:ty),+) => { $(impl T for $t { fn double(&self) -> u32 { self.x * 2 } })* } } impl_T!(for A, B); fn main() {} 

Poiché le parti interne delle tue strutture sono le stesse / condividono componenti comuni, dovresti estrarle in una struttura comune e incorporare la parte comune nelle strutture padre. La struttura comune avrebbe l’implementazione “complicata” del tratto e quindi le implementazioni dei tratti della struttura genitore delegherebbero all’implementazione comune:

 trait T { fn double(&self) -> u32; } struct A { common: Common, } impl T for A { fn double(&self) -> u32 { self.common.double() } } struct B { common: Common, } impl T for B { fn double(&self) -> u32 { self.common.double() } } struct Common { x: u32, } impl T for Common { fn double(&self) -> u32 { self.x * 2 } } 

Qualsiasi codice migliore richiederà modifiche alla lingua. Due possibili percorsi:

  • Campi in tratti
  • Delegazione