2015-11-05 14 views
5

Dato il seguente struct e impl:Tornando iteratore di un Vec in un RefCell

use std::slice::Iter; 
use std::cell::RefCell; 

struct Foo { 
    bar: RefCell<Vec<u32>>, 
} 

impl Foo { 
    pub fn iter(&self) -> Iter<u32> { 
     self.bar.borrow().iter() 
    } 
} 

fn main() {} 

ricevo un messaggio di errore su un problema di vita:

error: borrowed value does not live long enough 
    --> src/main.rs:9:9 
    | 
9 |   self.bar.borrow().iter() 
    |   ^^^^^^^^^^^^^^^^^ does not live long enough 
10 |  } 
    |  - temporary value only lives until here 
    | 
note: borrowed value must be valid for the anonymous lifetime #1 defined on the body at 8:36... 
    --> src/main.rs:8:37 
    | 
8 |  pub fn iter(&self) -> Iter<u32> { 
    | _____________________________________^ starting here... 
9 | |   self.bar.borrow().iter() 
10 | |  } 
    | |_____^ ...ending here 

Come io sono in grado di tornare e l'uso bar s iteratore?

risposta

9

Non è possibile farlo perché consente di aggirare i controlli di runtime per le violazioni di unicità.

RefCell fornisce un modo per "rinviare" i controlli di esclusività della mutabilità in runtime, in cambio consentendo la mutazione dei dati contenuti all'interno tramite riferimenti condivisi. Questo viene fatto usando guardie RAII: è possibile ottenere un oggetto guardia utilizzando un riferimento condiviso per RefCell, e quindi accedere ai dati all'interno RefCell utilizzando questo oggetto guardia:

&'a RefCell<T>  -> Ref<'a, T> (with borrow) or RefMut<'a, T> (with borrow_mut) 
&'b Ref<'a, T>  -> &'b T 
&'b mut RefMut<'a, T> -> &'b mut T 

Il punto chiave qui è che 'b è diverso da 'a , che consente di ottenere riferimenti &mut T senza avere un riferimento &mut allo RefCell. Tuttavia, questi riferimenti saranno invece collegati alla guardia e non potranno vivere più a lungo della guardia. Questo viene fatto intenzionalmente: i distruttori Ref e RefMut disattivano le varie bandiere all'interno del loro RefCell per forzare i controlli di mutabilità e forzare il panico borrow() e borrow_mut() se questi controlli falliscono.

La cosa più semplice che si può fare è quello di restituire un wrapper Ref, un riferimento al quale avrebbe implementare IntoIterator:

use std::cell::Ref; 

struct VecRefWrapper<'a, T: 'a> { 
    r: Ref<'a, Vec<T>> 
} 

impl<'a, 'b: 'a, T: 'a> IntoIterator for &'b VecRefWrapper<'a, T> { 
    type IntoIter = Iter<'a, T>; 
    type Item = &'a T; 

    fn into_iter(self) -> Iter<'a, T> { 
     self.r.iter() 
    } 
} 

(provate on playground)

Non è possibile implementare IntoIterator per VecRefWrapper direttamente perché quindi l'interno Ref verrà consumato da into_iter(), dando essenzialmente la stessa situazione in cui ti trovi ora.

+0

La vita è così dannatamente dura! Congratulazioni per averlo compreso e spiegato. – Moebius

Problemi correlati