2014-09-03 44 views
4

我發現Rust破壞了一些舊的代碼,我決定修復它。令人遺憾的是,看起來終身參考文獻已經發生了很大變化,出現了一些奇怪的事情。 字段Counter.data是不相關的,它只是用來顯示我使用的一些數據,它是對通用內容的引用。Rust and old iterator pattern中的生存期

下面是代碼:

struct Counter <'c, T: 'c> { 
    val: u32, 
    data: &'c T 
} 

struct CounterIterator<'c, T:'c> { 
    iter: &'c mut Counter<'c, T>, 
    num: u32 
} 

impl<'r, T> Iterator<u32> for CounterIterator<'r, T> { 
    fn next(&mut self) -> Option<u32> { 
     if self.num == 0 { 
      None 
     } else { 
      self.num -= 1; 
      self.iter.incr() 
     } 
    } 
} 

impl<'c, T> Counter <'c, T> { 
    fn new(dataz: &'c T) -> Counter<'c, T> { 
     Counter { 
      val: 0u32, 
      data: dataz 
     } 
    } 

    fn incr(&mut self) -> Option<u32> { 
     self.val += 1; 
     println!("{}", self.val); 
     Some(self.val) 
    } 

    fn iter(&'c mut self, num: u32) -> CounterIterator<'c, T> { 
     CounterIterator { 
      iter: self, 
      num: num 
     } 
    } 
} 

fn main() { 
    let val = 11u; 
    let mut cnt = Counter::new(&val); 
    for i in range(0,2u) { 
     cnt.incr(); 
    } 

    for i in cnt.iter(3) { 

    } 

    cnt.incr(); // <- commenting this out "fixes" the problem 
    // Otherwise the error is 
    // note: previous borrow of `cnt` occurs here; the mutable borrow prevents 
    // subsequent moves, borrows, or modification of `cnt` until the borrow ends 

} 

什麼是這裏的錯誤呢? 我該如何做到這一點,以便'迭代器'成語在退出循環時結束借入,而不是在其定義的塊的末尾? 另外,明確的生活時間T:'c做什麼?

爲了記錄我試圖在使用中實現類似於str.chars()的Iterator API。如果有更好的方法去做,請告訴我。

回答

2

fn iter中,&'c mut self關係self的可變借到Counter的壽命'c。在您撥打cnt.incr()時,您不能借用cnt,因爲.... cnt仍然存在(所以&'c mut self仍然在借用它)。

一種可能的方法,使你的代碼工作是在Counter移動data而不是存儲借來的引用,就像這樣:

struct Counter <T> { 
    val: u32, 
    data: T 
} 

如果你需要保留的數據爲基準,另一種選擇是向CounterIterator結構中引入第二個命名生命期,以便Counter的可變借入可以比Counter本身更短。

// we now have a shorter lifetime ('s) and a longer one ('l). This is 
// expressed to the compiler by the 'l: 's bound that says "'l lives 
// at least as long as 's" 
struct CounterIterator<'s, 'l: 's, T: 'l> { 
    iter: &'s mut Counter<'l, T>, 
    num: u32 
} 

impl<'c, T> Counter <'c, T> { 
// ... 
    // now the &mut self can live as long as CounterIterator, not necessarily as 
    // long as Counter. This allows it to be released as soon as the iteration 
    // is over and CounterIterator goes out of scope 
    fn iter<'a>(&'a mut self, num: u32) -> CounterIterator<'a,'c, T> { 
     CounterIterator { 
      iter: self, 
      num: num 
     } 
    } 
} 

作爲參考,由於語言還是有點變化不定:

$ rustc -v 
rustc 0.12.0-pre-nightly (2e3858179 2014-09-03 00:51:00 +0000) 
+0

只是微微評論。儘管我沒有使用這個解決方案,但它是幾個正確的解決方案之一。其他解決方案包括通過使用'Cell'放下可變性,或者等到借用檢查器支持非詞法範圍。 – 2014-09-05 15:34:29

+1

@DanielFath是的,還有其他的方法。還有一個你定義CounterIterator有兩個生命週期(但它有點複雜):http://is.gd/eMsLJd – 2014-09-06 19:14:08

+0

實際上,這是我正在尋找的解決方案。我從來沒有設法使生命時間正確工作。你可以添加它,所以它不會被pastebin /圍欄意外刪除? – 2014-09-06 20:44:32