2014-07-20 7 views
9

Ho riscontrato un problema durante l'utilizzo dei parametri di durata per le strutture. Non sono sicuro al 100% come descrivere il problema, ma ho creato un caso banale che mostra il mio errore di compilazione.Errore di durata della ruggine previsto per il ciclo di vita del calcestruzzo ma durata illimitata prefissata

struct Ref; 

struct Container<'a> { 
    r : &'a Ref 
} 

struct ContainerB<'a> { 
    c : Container<'a> 
} 

trait ToC { 
    fn to_c<'a>(&self, r : &'a Ref) -> Container<'a>; 
} 

impl<'a> ToC for ContainerB<'a> { 
    fn to_c(&self, r : &'a Ref) -> Container<'a> { 
    self.c 
    } 
} 

L'errore che sto ottenendo con questo è

test.rs:16:3: 18:4 error: method `to_c` has an incompatible type for trait: expected concrete lifetime, but found bound lifetime parameter 'a 
test.rs:16 fn to_c(&self, r : &'a Ref) -> Container<'a> { 
test.rs:17  self.c 
test.rs:18 } 
test.rs:16:48: 18:4 note: expected concrete lifetime is the lifetime 'a as defined on the block at 16:47 
test.rs:16 fn to_c(&self, r : &'a Ref) -> Container<'a> { 
test.rs:17  self.c 
test.rs:18 } 
error: aborting due to previous error 

Ho provato molte variazioni e proprio non riesco a ottenere questa cosa per compilare. Ho trovato un altro post qui (How to fix: expected concrete lifetime, but found bound lifetime parameter) ma sembra aggirare il problema invece di risolverlo. Non riesco davvero a capire perché il problema abbia origine. Il & Ref viene passato attraverso le mosse quindi dovrebbe funzionare correttamente?

Qualche idea? Grazie per tutto l'aiuto.

risposta

13

Confrontiamo le due definizioni. In primo luogo, il metodo di trait:

fn to_c<'a>(&self, r: &'a Ref) -> Container<'a>; 

e l'implementazione:

fn to_c(&self, r: &'a Ref) -> Container<'a>; 

Vedi la differenza? Quest'ultimo non ha <'a>. <'a> è stato specificato altrove; il fatto che abbia lo stesso nome non ha importanza: è una cosa completamente diversa.

punto di vista funzionale, la vostra definizione trait dice che il contenitore restituita avrà un riferimento al suo interno per qualcosa da r, ma nulla da self. Può utilizzare self all'interno del metodo, ma potrebbe non memorizzare alcun riferimento ad esso nel valore restituito.

tuo metodo di definizione, tuttavia, sta utilizzando un 'a che lega le vite di r e restituita Container-self (cioè, per l'oggetto stesso, senza il riferimento-il ρ₂ in &'ρ₁ T<'ρ₂> -è una sottile, ma a volte significative differenza), mentre la definizione del tratto non aveva tale connessione.

È possibile eseguire le due corrispondenze inserendo <'a> nella definizione del metodo nell'implementazione. Ma tieni a mente che questo sta oscurando lo 'a da ContainerB<'a>; è non lo stesso 'a! È meglio dargli un altro nome; per comodità, farò il cambiamento viceversa, cambiando sul impl anziché il metodo (sia farebbe):

impl<'b> ToC for ContainerB<'b> { 
    fn to_c<'a>(&self, r: &'a Ref) -> Container<'a> { 
     self.c 
    } 
} 

Ma ora, naturalmente, avete un problema: il valore di ritorno è di digitare Container<'b> (perché è il campo c in un), ma la tua firma richiede Container<'a> (qualcosa che utilizza un riferimento da r, non da self).

Un modo per risolvere il problema è specificare la durata di &self come 'a sia nella definizione di tratto che nell'implementazione; nell'implementazione, ciò richiederebbe che 'b fosse maggiore o uguale a 'a (in virtù del fatto che è stato preso con successo un riferimento con durata 'a a un oggetto con durata pari a 'b e che l'oggetto deve superare il riferimento) e quindi a causa della sottotipizzazione ('a è un sottotipo di 'b) Container<'b> dovrebbe essere forzato in modo sicuro a Container<'a>.

Questi tipi di argomenti della vita sono difficili da pensare quando non si ha familiarità con loro; ma col tempo diventano abbastanza naturali.

+1

Un'altra correzione sarebbe 'tratto ToC <'a> {fn to_c (& self, r: & 'a Ref) -> Contenitore <'a>; } '. – huon

+0

Oh sì, quindi "impl <'a> ToC <'a> per ContainerB <'a>". –

+0

Questo sicuramente aiuta molto e risolve alcuni dei miei pensieri sbagliati (ad esempio l'ombreggiamento a vita)! Grazie. Questo risolve questo caso al 100%, ma non riesco a applicarlo a un altro. Ho scritto questa domanda qui: http://stackoverflow.com/questions/24853111/rust-lifetime-error-expected-concrete-lifetime-part-2) – luke