2015-11-05 71 views
5

鑑於以下structimpl返回A 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。然而,這些參考文獻將與警衛聯繫起來,並且不能比警衛活得更長。這是故意完成的:RefRefMut析構器在其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

您不能VecRefWrapper實現IntoIterator直接因爲內部Ref將被into_iter()消耗,給你基本上與你現在一樣的情況。

+0

終身是如此艱難!恭喜理解並解釋它。 – Moebius