2014-11-19 9 views
6

Editor's note: This code example is from a version of Rust prior to 1.0 and is not syntactically valid Rust 1.0 code. Updated versions of this code produce different errors, but the answers still contain valuable information.È possibile memorizzare un valore in una struttura attraverso un tratto?

Ho provato questo con e senza Box, con e senza vite:

trait TraitToImpl { 
    fn do_something(self, val: i32); 
} 

struct Cont { 
    value: i32, 
} 

impl TraitToImpl for Cont { 
    fn do_something(self, val: i32) { 
     println!("{}", val); 
    } 
} 

struct StoreTrait<'a> { 
    field: Box<TraitToImpl + 'a>, 
} 

fn main() { 
    let cont = Box::new(Cont { value: 12 }) as Box<TraitToImpl>; 
    let a = StoreTrait { field: cont }; 
    a.field.do_something(123); 
} 

Tutto quello che ottiene è questo errore:

error: cannot convert to a trait object because trait `TraitToImpl` is not object-safe

risposta

8

Il problema è, come dice il messaggio di errore , che il tratto TraitToImpl non è sicuro per gli oggetti. Cioè, è non sicuro usare quel particolare tratto attraverso un riferimento (cioè &TraitToImpl o Box<TraitToImpl>

In particolare, il metodo do_something prende self per valore consideri:.. Come fa il compilatore chiamata questo metodo su Cont che è stato collocato in una Box<TraitToImpl>? ha per copiare il valore in un argomento di tipo Cont (che è ciò che il impl si aspetta), ma questa chiamata deve lavorare per qualsiasi tipo di qualsiasi dimensione che potrebbe implementare TraitToImpl!

Risultato pratico: se si dispone di un carattere che contiene il valore di riferimento self o di generici, non può essere utilizzato tramite un riferimento. Nel momento in cui avviene la chiamata, il compilatore non ha più abbastanza informazioni per generare effettivamente il codice necessario.

Forse provare a prendere &self invece? :)

+0

Grazie mille. Questo messaggio di errore non era chiaro per me. E, se capisco correttamente, è impossibile passare per valore attraverso il tratto. –

3

di capire l'origine di questo errore, ma può anche aiutare a cercare la definizione di oggetto-safe nel Object Safety RFC:

We say a method m on trait T is object-safe if it is legal (in current Rust) to call x.m(...) where x has type &T , i.e., x is a trait object. If all methods in T are object-safe, then we say T is object-safe.

Come sottolineato da @DK, x.do_something(...) è illegale poiché TraitToImpl non può essere passato per valore.

Si noti che la sicurezza dell'oggetto può anche essere violata derivando da un tratto non protetto da oggetti. Per esempio.

trait TraitToImpl : Clone { 
    fn do_something(&self, val: int); // this method is object-safe 
} 

non sarebbe oggetto sicura perché Clone sé ha un metodo non-oggetto-safe (fn clone(&self) -> Self).

Problemi correlati