2015-09-04 9 views
5

Molte librerie consentono di definire un tipo che implementa un dato trait da utilizzare come gestore di richiamata. Ciò richiede di raggruppare tutti i dati necessari per gestire l'evento insieme in un singolo tipo di dati, il che complica i prestiti.Qual è il modo più rapido e idiomatico di mutare più campi della struttura contemporaneamente?

Ad esempio, mio consente di implementare Handler e fornire la struttura quando si run the EventLoop. Si consideri un esempio con questi tipi di dati banalizzati:

struct A { 
    pub b: Option<B> 
}; 

struct B; 

struct MyHandlerType { 
    pub map: BTreeMap<Token, A>, 
    pub pool: Pool<B> 
} 

vostro gestore ha una mappa da Token a elementi di tipo A. Ogni articolo di tipo A può o non può avere già un valore associato di tipo B. Nel gestore, si desidera cercare il valore A per un dato Token e, se non ha già un valore B, ottenerne uno tra del gestore.

impl Handler for MyHandlerType { 
    fn ready(&mut self, event_loop: &mut EventLoop<MyHandlerType>, 
      token: Token, events: EventSet) { 
     let a : &mut A = self.map.get_mut(token).unwrap(); 
     let b : B = a.b.take().or_else(|| self.pool.new()).unwrap(); 
     // Continue working with `a` and `b` 
     // ... 
    } 
} 

In questo accordo, anche se è intuitivo possibile vedere che self.map e self.pool sono entità distinte, il correttore prestito lamenta che self è già preso in prestito (via self.map) quando andiamo per accedere self.pool.

Un possibile approccio a questo sarebbe quello di avvolgere ogni campo in MyHandlerType in Option<>. Poi, all'inizio della chiamata al metodo, take() quei valori su self e ripristinarli al termine della chiamata:

struct MyHandlerType { 
    // Wrap these fields in `Option` 
    pub map: Option<BTreeMap<Token, A>>, 
    pub pool: Option<Pool<B>> 
} 
// ... 

fn ready(&mut self, event_loop: &mut EventLoop<MyHandlerType>, 
     token: Token, events: EventSet) { 
    // Move these values out of `self` 
    let map = self.map.take().unwrap(); 
    let pool = self.pool.take().unwrap(); 

    let a : &mut A = self.map.get_mut(token).unwrap(); 
    let b : B = a.b.take().or_else(|| self.pool.new()).unwrap(); 
    // Continue working with `a` and `b` 
    // ... 

    // Restore these values to `self` 
    self.map = Some(map); 
    self.pool = Some(pool); 
} 

Questo funziona si sente, ma un po 'Kluge-y. Introduce inoltre il sovraccarico dei valori di spostamento all'interno e all'esterno di self per ciascuna chiamata di metodo.

Qual è il modo migliore per farlo?

risposta

11

Per ottenere riferimenti mutabili simultanei a diverse parti della struttura, utilizzare la destrutturazione. Esempio here.

struct Pair { 
    x: Vec<u32>, 
    y: Vec<u32>, 
} 

impl Pair { 
    fn test(&mut self) -> usize { 
     let Pair{ ref mut x, ref mut y } = *self; 
     // Both references coexist now 
     return x.len() + y.len(); 
    } 
} 

fn main() { 
    let mut nums = Pair { 
     x: vec![1, 2, 3], 
     y: vec![4, 5, 6, 7], 
    }; 
    println!("{}", nums.test()); 
} 
+1

!!! Grazie! Sapevo di destrutturare, ma non avevo idea che potessi usarlo per ottenere riferimenti simultanei mutabili. Questo è stato un grande aiuto! – zslayton