2016-11-07 143 views
2

我知道Lifetime in Iterator impl,但我想了解更多的細節來幫助我正確理解。迭代器返回自己的引用

我想寫一個無限Iterator,返回&[0],&[0, 1],&[0, 1, 2]等。我想這樣寫:

struct Countings(Vec<usize>); 

impl Countings { 
    fn new() -> Countings { Countings(vec![]) } 
} 

impl Iterator for Countings { 
    type Item = &[usize]; 

    fn next(&mut self) -> Option<Self::Item> { 
     self.0.push(self.0.len()); 
     Some(self.0.as_slice()) 
    } 
} 

我不能因爲類型Countings::Item沒有一輩子。

error[E0106]: missing lifetime specifier 
--> src/lib.rs:8:17 
    | 
8 |  type Item = &[usize]; 
    |    ^expected lifetime parameter 

所以我加一個。它必須受impl Iterator的約束。這反過來需要在struct Countings上有一個生命週期參數。到目前爲止,我在這裏:

struct Countings<'a>(Vec<usize>); 

impl<'a> Countings<'a> { 
    fn new() -> Countings<'a> { Countings(vec![]) } 
} 

impl<'a> Iterator for Countings<'a> { 
    type Item = &'a [usize]; 

    fn next(&mut self) -> Option<Self::Item> { 
     self.0.push(self.0.len()); 
     Some(self.0.as_slice()) 
    } 
} 

現在我有一個不同的錯誤:

error[E0392]: parameter `'a` is never used 
--> src/lib.rs:1:18 
    | 
1 | struct Countings<'a>(Vec<usize>); 
    |     ^^ 
    | 
    = help: consider removing `'a` or using a marker such as `std::marker::PhantomData` 

我好好考慮一下:

use std::marker::PhantomData; 

struct Countings<'a>(Vec<usize>, PhantomData<&'a [usize]>); 

impl<'a> Countings<'a> { 
    fn new() -> Countings<'a> { Countings(vec![], PhantomData) } 
} 

impl<'a> Iterator for Countings<'a> { 
    type Item = &'a [usize]; 

    fn next(&mut self) -> Option<Self::Item> { 
     self.0.push(self.0.len()); 
     Some(self.0.as_slice()) 
    } 
} 

但無濟於事:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements 
    --> src/lib.rs:14:25 
    | 
14 |    Some(self.0.as_slice()) 
    |       ^^^^^^^^ 

問題1:什麼是「衝突的要求s「嗎?

問題2:answer cited above表示Item必須借用Iterator包裝的東西。我已閱讀std::slice::Windows的來源,這是一個很好的例子。然而,在我的情況下,我想要改變Vec每次調用next()。那可能嗎?

回答

2

Question 1: What are the "conflicting requirements"?

您嘗試返回的借款沒有使用壽命'a,如承諾的那樣。相反,它具有與self相同的生命週期。如果next簽名寫於全,那就是:

fn next<'b>(&'b mut self) -> Option<&'a [usize]> 

返回一個Option<&'b [usize]>(終身的'b代替'a)將是有效的,如果不是因爲它違反了合同的事實Iterator特徵。但是,它會凍結self,直到結果被刪除;即您不能撥打next兩次,並將兩個呼叫的結果一起使用。這是因爲每次撥打next可能會使先前返回的切片失效;推送到Vec可以重新定位內存中的存儲空間以便爲其他元素騰出空間,因此切片中的指針將不再有效。

Question 2: The answer cited above says that Item must borrow from something that the Iterator wraps. I have read the source for std::slice::Windows which is a good example. However, in my case I want to mutate the Vec each time next() is called. Is that possible?

這是不可能的Iterator特質做到這一點,所以你將無法使用for環路上你的結構。但是,你可以用普通的方法來做到這一點(上面提到的警告)。

struct Countings(Vec<usize>); 

impl Countings { 
    fn new() -> Countings { Countings(vec![]) } 

    fn next<'a>(&'a mut self) -> &'a [usize] { 
     let item = self.0.len(); 
     self.0.push(item); 
     self.0.as_slice() 
    } 
} 
2

正如弗朗西斯所說,在迭代過程中不可能修改基礎向量。但是,如果你以某種方式必須指定綁定的迭代的可能性,那麼事情就好辦多了:

  • 您可以創建矢量[0, 1, 2, ...]
  • ,然後創建一個返回日益增長片的迭代器,至矢量

就在迭代器的長度:

struct EverGrowingIterator<'a, T: 'a> { 
    slice: &'a [T], 
    current: usize, 
} 

impl<'a, T> Iterator for EverGrowingIterator<'a, T> { 
    type Item = &'a [T]; 

    fn next(&mut self) -> Option<&'a [T]> { 
     if self.current >= self.slice.len() { 
      None 
     } else { 
      self.current += 1; 
      Some(&self.slice[0..self.current]) 
     } 
    } 
} 

然後:

fn ever_growing<'a, T>(slice: &'a [T]) -> EverGrowingIterator<'a, T> { 
    EverGrowingIterator { slice: slice, current: 0 } 
} 

fn main() { 
    let v = vec![0, 1, 2]; 
    for s in ever_growing(&v) { 
     println!("{:?}", s); 
    } 
} 

會打印:

[0] 
[0, 1] 
[0, 1, 2] 

如果你需要適應這個無限增長,你需要考慮創建一個自定義容器(不是Vec),同時保留引用將增長到之前的片段。可以使用類似RefCell<Vec<Box<[T]>>>的東西。

+0

謝謝。你的答案有一些有用的東西。如果我能接受這兩個答案,但我認爲弗朗西斯的回答更好地集中在我的兩個問題上。 – apt1002