2015-11-05 2 views
5

Учитывая следующие struct и impl:Возвращение итератора в Vec в 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() {} 

я получаю сообщение об ошибке пожизненного выпуске:

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 

Как я смог вернуться и использование bar s итератор?

ответ

9

Вы не можете сделать это, потому что это позволит вам обойти проверки времени выполнения для нарушений уникальности.

RefCell предоставляет вам возможность «отсрочить» проверку исключительности в соответствии со временем выполнения, в обмен, разрешая мутацию данных, которые она хранит внутри, посредством общих ссылок. Это делается с помощью RAII охранников: вы можете получить объект охраны, используя общую ссылку на RefCell, а затем получить доступ к данным внутри RefCell с помощью этого защитного объекта:

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

Ключевым моментом здесь является то, что 'b отличается от 'a , что позволяет получить &mut T ссылки без ссылки &mut на номер RefCell. Однако эти ссылки будут связаны с охраной и не смогут прожить дольше, чем охранник. Это делается намеренно: Ref и RefMut деструкторы переключают различные флаги внутри своих RefCell, чтобы принудительно выполнить проверки на изменчивость и принудительно установить borrow() и borrow_mut() панику, если эти проверки не пройдены.

Самое простое, что вы можете сделать, это вернуть обертку вокруг Ref, ссылка на который будет осуществлять 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() 
    } 
} 

(попробуйте on playground)

Вы не можете реализовать IntoIterator для VecRefWrapper потому что тогда внутренний Ref будет потребляться into_iter(), что дает вам практически ту же ситуацию, в которой вы сейчас находитесь.

+0

Срок службы так проклят! Поздравляем за понимание и объяснение. – Moebius