2016-11-18 30 views
0

深化了包裹向量执行IntoIteratorthe Rust book,我也试图实施IntoIterator的参考到包装,按the following code (Playground link)的例子:我是否错误地实现了IntoIterator作为参考,或者这是一个应该报告的Rust错误?

struct VecWrapper(Vec<i32>); 

impl VecWrapper { 
    fn iter(&'static self) -> Iter { 
     Iter(Box::new(self.0.iter())) 
    } 
} 

struct Iter(Box<Iterator<Item = &'static i32>>); 

impl Iterator for Iter { 
    type Item = &'static i32; 
    fn next(&mut self) -> Option<Self::Item> { 
     self.0.next() 
    } 
} 

impl IntoIterator for &'static VecWrapper { 
    type Item = &'static i32; 
    type IntoIter = Iter; 
    fn into_iter(self) -> Self::IntoIter { 
     self.iter() 
    } 
} 

fn main() { 
    // let test = vec![1, 2, 3]; // obviously, works 
    let test = VecWrapper(vec![1, 2, 3]); // not working 
    for v in &test { 
     println!("{}", v); 
    } 
} 

虽然实现汇总,尝试在main使用它不会出现以下错误:

rustc 1.15.0-nightly (43006fcea 2016-11-15) 
error: `test` does not live long enough 
    --> <anon>:31:15 
    | 
31 |  for v in &test { 
    |    ^^^^ does not live long enough 
... 
34 | } 
    | - borrowed value only lives until here 
    | 
    = note: borrowed value must be valid for the static lifetime... 

此代码是由很多东西我真的想为使用使用简化仅使用'static生命周期,使用现有的包含类型,并使用i32作为内部(迭代)类型,但它只能用于解释问题。

Edit_Added:虽然以不使用'static和使用+ 'a与性状接受的答案解决问题的第一部分,我还是很具有实际的代码,这是一个LazyList实现的问题。我已经发布,作为separate question

+0

你应该回滚你的编辑[并提出一个新问题](http://meta.stackoverflow.com/q/253762/155423) - 当然,搜索以确保它不是重复的。 – Shepmaster

+0

@Shepmaster,我按照你的建议做了,[新的问题在这里](http://stackoverflow.com/questions/40687955/am-i-incorrectly-implementing-intoiterator-for-a-reference-to-a- lazylist-impleme)。 – GordonBGood

回答

3

您正确实施为引用迭代VecWrapper s表示现场为节目的整个长度 - 'static寿命。

有机会,你想有一个通用的生命。然后,这个生命周期将被提供一个具体的生命周期,每个实例化都是独一无二的通常情况下,我们是懒惰,只是给这一辈子名称'a

struct VecWrapper(Vec<i32>); 

impl VecWrapper { 
    fn iter(&self) -> Iter { 
     Iter(Box::new(self.0.iter())) 
    } 
} 

struct Iter<'a>(Box<Iterator<Item = &'a i32> + 'a>); 

impl<'a> Iterator for Iter<'a> { 
    type Item = &'a i32; 

    fn next(&mut self) -> Option<Self::Item> { 
     self.0.next() 
    } 
} 

impl<'a> IntoIterator for &'a VecWrapper { 
    type Item = &'a i32; 
    type IntoIter = Iter<'a>; 

    fn into_iter(self) -> Self::IntoIter { 
     self.iter() 
    } 
} 

fn main() { 
    let test = VecWrapper(vec![1, 2, 3]); // not working 
    for v in &test { 
     println!("{}", v); 
    } 
} 

重要的变化:

  • Box<Iterator<Item = &'a i32> + 'a> - + 'a加入。这是必要的,因为性状对象将假定不存在引用具有短生命周期的任何内部值。
  • Item类型现在是&'a i32
  • 通用生命周期在很多地方都有声明,并在其他许多地方提供(<'a>)。

通常情况下,不会有一个理由,在这里使用一个特性对象。我只是直接嵌入迭代器:

struct Iter<'a>(std::slice::Iter<'a, i32>); 

这避免了需要有任何间接,这是在这种情况下,未使用的反正。此外,它更明显地结合了生命。

+0

我已经知道如何使用''a''而不是''static'来实现,就像我在问题中提到的那样,只是简化了并且已经在相同的地方使用''a''的版本;我错过了'Iter struct'定义中的'+'a'(你的第一点)。为此,我非常感谢你。对于读者来说,正如@Shpmaster所说的那样,使用''static'在这里不起作用,即使使用'+'也是如此,因为迭代/ for循环中的常用用法将在另一个函数/块中。 – GordonBGood

+0

虽然我同意你的最后一个建议可能会使代码在生命周期中更清晰,但它需要深入了解标准库的内部知识,并增加了初始化的复杂性,例如'std :: slice :: Iter {ptr: self.0 [0],end:(self.0 [0] as * const i32).offset(self.0.len()asize),_marker:std :: marker :: PhantomData}',这是'这可能是因为'ptr','end'和'_marker'字段是私有的,无法在模块外初始化。这是不可用的,是吗? – GordonBGood

+0

@GordonBGood *它需要深入了解标准库的内部知识* - 什么? [只需...调用常规方法](http://play.integer32.com/?gist=fe12ab6a13ba9e6ec722d430bb1bc20a​​&version=stable)。 – Shepmaster

相关问题