2016-11-07 91 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