2015-11-05 24 views
5

otrzymuje następujące struct i impl:Wracając iterator o Vec w 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() {} 

otrzymuję komunikat o błędzie o emisji Żywotność:

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 

Jak jestem w stanie wrócić i użytkowania bar s iterator?

Odpowiedz

9

Nie można tego zrobić, ponieważ pozwoliłoby to na obejście sprawdzeń w czasie rzeczywistym pod kątem naruszenia wyjątków.

RefCell zapewnia sposób "odroczenia" kontroli wyłączności mutability do środowiska wykonawczego, w zamian umożliwiając mutację danych przechowywanych wewnątrz poprzez udostępnione odniesienia. Odbywa się to za pomocą strażników RAII: można uzyskać obiekt osłony za pomocą udostępnionego odniesienie do RefCell, a następnie uzyskać dostęp do danych wewnątrz RefCell użyciu tego obiektu Strażnik:

&'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 

Kluczową kwestią jest to, że 'b różni się od 'a , który pozwala uzyskać referencje &mut T bez odniesienia do &mut odniesienia do RefCell. Jednak te odniesienia będą połączone ze strażnikiem i nie mogą żyć dłużej niż strażnik. Dokonuje się tego celowo: Ref i RefMut destruktory przełączają różne flagi wewnątrz swoich RefCell, aby wymusić kontrolę poprawności i wymusić panikę, jeśli te kontrole się nie powiodą.

Najprostszą rzeczą, jaką możesz zrobić, to wrócić owijkę wokół Ref, odniesienie do których wdrożenie 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() 
    } 
} 

(spróbuj on playground)

Nie można wdrożyć IntoIterator dla VecRefWrapper bezpośrednio, ponieważ wtedy wewnętrzny Ref zostanie zużyty przez into_iter(), dając w zasadzie taką samą sytuację, w jakiej teraz jesteś.

+0

Żywotność jest tak cholernie trudna! Gratulacje za zrozumienie i wyjaśnienie. – Moebius