2015-03-30 12 views
9

Ho un tratto con un tipo associato e una struttura generica ::corrispondenza di un parametro generico a un tipo associato in un impl

trait Generator { 
    type Foo; 
    fn generate(&self) -> Self::Foo; 
} 

struct Baz<A, B> 
where 
    A: Generator, 
{ 
    generator: A, // will be some struct implementing Generator, but the exact type will vary 
    vec: Vec<B>, // Each element will be A::Foo 
} 

voglio generate e mettila nel mio vettore:

impl<A: Generator, B> Baz<A, B> { 
    fn addFoo(&mut self) { 
     self.vec.push(self.generator.generate()); 
    } 
} 

Uh-oh! Errore di compilazione:

error[E0308]: mismatched types 
    --> src/main.rs:16:27 
    | 
16 |    self.vec.push(self.generator.generate()); 
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found associated type 
    | 
    = note: expected type `B` 
       found type `<A as Generator>::Foo` 

Va bene, devo spiegare al compilatore che B è lo stesso di A::Foo; proviamo con where:

impl<A: Generator, B> Baz<A, B> 
where 
    A::Foo = B, 
{ 

che non aiuta:

error: equality constraints are not yet supported in where clauses (#20041) 
    --> src/main.rs:16:5 
    | 
16 |  A::Foo = B, 
    |  ^^^^^^^^^^ 

Hmm, eguali. Forse posso farlo con l'operatore del colon, invece?

impl<A: Generator, B> Baz<A, B> 
where 
    B: A::Foo, 
{ 
error[E0405]: cannot find trait `Foo` in `A` 
    --> src/main.rs:16:11 
    | 
16 |  B: A::Foo, 
    |   ^^^ not found in `A` 

No, ora è lamentarsi A. Forse dovrei dire Generator?

impl<A: Generator, B> Baz<A, B> 
where 
    B: Generator::Foo, 
{ 
error[E0404]: expected trait, found associated type `Generator::Foo` 
    --> src/main.rs:16:8 
    | 
16 |  B: Generator::Foo, 
    |  ^^^^^^^^^^^^^^ not a trait 

Bene buon lavoro, compilatore - è non un tratto; è un tipo associato, ma questo non mi dice come scrivere una clausola where che la abbini.

+0

Sei sicuro è necessario sottotipo Generator? – llogiq

risposta

15

I must explain to the compiler that B is the same as A::Foo

C'è una sintassi speciale per esso:

impl<A, B> Baz<A, B> 
where 
    A: Generator<Foo = B>, 
{ 
    fn add_foo(&mut self) { 
     self.vec.push(self.generator.generate()); 
    } 
} 
+0

Penso che questa sia la risposta a ciò che chiede, non a ciò che vuole. Grazie, non sapevo di questa sintassi. –

4

Si potrebbe sbarazzarsi della argomento generico B e invece di condizionare B, passare direttamente A::Foo come secondo argomento generico per Baz, ma non sono sicuro se il vostro problema reale corrisponde l'esempio semplificato hai mostrato.

impl<A: Generator> Baz<A, A::Foo> { 
    fn addFoo(&mut self) { 
     self.vec.push(self.generator.generate()); 
    } 
} 
8

Il trucco è quello di avere un solo parametro generico:

trait Generator { 
    type Foo; 
    fn generate(&self) -> Self::Foo; 
} 

struct Baz<G> 
where 
    G: Generator, 
{ 
    generator: G, 
    vec: Vec<G::Foo>, 
} 

impl<G> Baz<G> 
where 
    G: Generator, 
{ 
    fn add_foo(&mut self) { 
     self.vec.push(self.generator.generate()); 
    } 
} 

Dal momento che il vettore conterrà G::Foo, possiamo in realtà solo dire che.

Lo stile Rust è snake_case, quindi l'ho aggiornato così come ho reso il parametro di tipo G per aiutare il lettore.

Problemi correlati