2015-07-20 1 views
6

So che i tratti e le sezioni non sono standardizzati, vale a dire che non è possibile conoscere le loro dimensioni al momento della compilazione, ad es. qualsiasi tipo può implementare un tratto, ma quel tipo potrebbe non essere ridimensionato.Implementazione del tratto dimensionato

Tuttavia, questo codice di esempio non significa che ogni tipo che implementa il tratto Foo deve implementare anche Sized?

trait Foo : Sized {} 

struct Bar(i64); 

impl Foo for Bar {} 

Se è così, perché non funziona?

impl From<Foo> for Bar { 
    fn from(foo: Foo) -> Bar { 
     Bar(64) 
    } 
} 
src\lib.rs:9:1: 15:2 error: the trait `core::marker::Sized` is not implemented for the type `Foo` [E0277] 
src\lib.rs:9 impl From<Foo> for Bar 
src\lib.rs:10 { 
src\lib.rs:11  fn from(foo: Foo) -> Bar { 
src\lib.rs:13   Bar(64) 
src\lib.rs:14  } 
       ... 
src\lib.rs:9:1: 15:2 note: `Foo` does not have a constant size known at compile-time 
src\lib.rs:9 impl From<Foo> for Bar 
src\lib.rs:10 { 
src\lib.rs:11  fn from(foo: Foo) -> Bar { 
src\lib.rs:13   Bar(64) 
src\lib.rs:14  } 

Quello che volevo fare - fornire al consumatore della biblioteca un tipo (lascia denominarlo Bar), e permettono di convertire in barre da qualsiasi altro tipo che implementa particolare Trait (lascia chiamalo Foo).

In realtà ho risolto passando Foo dal riferimento anziché dal valore, anche se non ero del tutto sicuro del motivo per cui il compilatore si lamenta, se è richiesto dagli implementatori alle dimensioni.

risposta

9

Perché non funziona?

Quando si dice che ogni è Sized, si sta nascondendo la verità a se stessi. Sì, ogni Foo è Sized ma in realtà ogni tipo ha una determinata dimensione a un certo punto. La vera informazione importante è che non stai dicendo quanto questa dimensione sia. Immaginate se Foo sia Foo, ma Foo è Foo (sono entrambi Sized, giusto?) Quale taglia si determina Foo? È lungo 8 o 1 byte? Questa domanda viene posta dal compilatore quando tenta di generare il codice per la funzione from(foo: Foo). Solitamente, Sized è piuttosto utilizzato in uno stile "forse" con la sintassi ?Sized, a indicare che la dimensione del tipo potrebbe essere sconosciuta in fase di compilazione.

Come risolverlo?

In genere si interrompe la parte : Sized e si utilizza la seguente sintassi, che è in realtà una specie di modello C++; dà al compilatore uno schizzo per scrivere il codice reale quando viene dato un tipo concreto con una determinata dimensione.

trait Foo {} 
struct Bar(i64); 
impl Foo for Bar {} 
impl<F: Foo> From<F> for Bar { 
    fn from(foo: F) -> Bar { 
     Bar(64) 
    } 
} 

(Questo sarà still error basata sul fatto che non si può reimplementare From a causa della std cassa, ma non è legato alla tua domanda iniziale.)

Si potrebbe anche usare una sintassi prestito &Foo nel argomento alla tua funzione. Ciò trasformerebbe la chiamata da invio statico a invio dinamico (read more here) ma in via eccezionale non è possibile farlo qui, poiché la firma è imposta dal carattere.

0

Il tratto Foo richiede che gli implementatori siano dimensionati. Ciò non significa che Foo stesso avrà una dimensione. Stai fraintendendo la sintassi del secondo esempio di codice e quindi non sono sicuro di ciò che stai effettivamente cercando di fare. Stai cercando questo?

impl From<i64> for Bar { 
    fn from(val: i64) -> Bar { 
     Bar(val) 
    } 
} 

O vuoi un modo per costruire una barra da qualsiasi numero intero con segno?

Qui abbiamo uno XY problem.