2015-06-05 12 views
5

mi piacerebbe implementare Deref e DefrefMut su una struttura che possiede un tratto in scatola, per esempio:Implementazione Deref su una struttura che possiede una caratteristica scatola

use std::ops::{Deref, DerefMut}; 

trait Quack { 
    fn quack(&self); 
} 

struct QuackWrap { 
    value: Box<Quack> 
} 

impl Deref for QuackWrap { 
    type Target = Box<Quack>; 

    fn deref<'a>(&'a self) -> &'a Box<Quack> { 
     &self.value 
    } 
} 

impl DerefMut for QuackWrap { 
    fn deref_mut<'a>(&'a mut self) -> &'a mut Box<Quack> { 
     &mut self.value 
    } 
} 

Questo non riesce a compilare con il seguente errore:

src/main.rs:14:5: 16:6 error: method `deref` has an incompatible type for trait: expected bound lifetime parameter 'a, found concrete lifetime [E0053] 
src/main.rs:14  fn deref<'a>(&'a self) -> &'a Box<Quack> { 
src/main.rs:15   &self.value 
src/main.rs:16  } 
src/main.rs:20:5: 22:6 error: method `deref_mut` has an incompatible type for trait: expected bound lifetime parameter 'a, found concrete lifetime [E0053] 
src/main.rs:20  fn deref_mut<'a>(&'a mut self) -> &'a mut Box<Quack> { 
src/main.rs:21   &mut self.value 
src/main.rs:22  } 

Se sostituisco Box<Quack> con Box<String> (o un tipo simile), funziona. Il problema è che Quack è un tratto. Ma non sono sicuro del perché abbia generato il messaggio di errore. Qualche idea?

La mia domanda è simile a another SO question, ma non proprio la stessa. In quella domanda, la struct ha un parametro type con il tratto come un vincolo. Mentre nella mia domanda, non esiste un parametro di tipo.

Non voglio confondere i problemi, ma c'è una buona ragione per cui ho bisogno di Box<Quack> nella mia applicazione. Cioè Non riesco a sostituire Quack con un parametro di tipo. Nel caso ti interessi, il motivo è discussed further in another SO question.

+0

'type Target = Box ;' è 'tipo Target = Box ;', e '&' a Box ' è '& 'a Box '. –

risposta

6

In caso di dubbio, aggiungere ulteriori annotazioni di corso della vita:

use std::ops::{Deref, DerefMut}; 

trait Quack { 
    fn quack(&self); 
} 

struct QuackWrap<'b> { 
    value: Box<Quack + 'b> 
} 

impl<'b> Deref for QuackWrap<'b>{ 
    type Target = Box<Quack + 'b>; 

    fn deref<'a>(&'a self) -> &'a Box<Quack + 'b> { 
     &self.value 
    } 
} 

impl<'b> DerefMut for QuackWrap<'b> { 
    fn deref_mut<'a>(&'a mut self) -> &'a mut Box<Quack + 'b> { 
     &mut self.value 
    } 
} 
+4

In particolare, questo aiuta perché 'struct QuackWrap {value: Box }' è equivalente a 'struct QuackWrap {value: Box }'. – Shepmaster

+0

@Shepmaster Grazie per la spiegazione. Non sapevo con esattezza quale era implicita la durata della vita, quindi ho lasciato la mia risposta come solo la soluzione. La risposta al motivo per cui questo si è rotto in primo luogo è abbastanza utile. –

+0

Grazie mille a tutti e due! – rlkw1024

1

in base alla risposta di Brian e la spiegazione di Shepmaster, ho aggiornato il mio codice come segue. Ho anche semplificato la struttura QuackWrap. (Che non era strettamente necessario, ma è senza dubbio lo stile meglio di quello che facevo prima.)

use std::ops::{Deref, DerefMut}; 

trait Quack { 
    fn quack(&self); 
} 

struct QuackWrap(Box<Quack>); 

impl Deref for QuackWrap { 
    type Target = Box<Quack + 'static>; 

    fn deref<'a>(&'a self) -> &'a Box<Quack + 'static> { 
     let QuackWrap(ref v) = *self; 
     v 
    } 
} 

impl DerefMut for QuackWrap { 
    fn deref_mut<'a>(&'a mut self) -> &'a mut Box<Quack + 'static> { 
     let QuackWrap(ref mut v) = *self; 
     v 
    } 
} 

Ci può essere un modo più conciso di destrutturare QuackWrap nelle deref e deref_mut implementazioni. Alcune di quelle regole di sintassi più oscure mi sfuggono. Ma per ora va bene.

+0

* Potrebbe esserci un modo più conciso ... * - I Newtype (e tutte le strutture tuple) offrono accessi di posizione. Ecco un [esempio leggermente più piccolo] (http://is.gd/Q6weUR) – Shepmaster

Problemi correlati