是否可以构建一个迭代器,该迭代器产生对它在next()中修改的对象的引用?

时间:2016-02-14 13:31:48

标签: rust

我正在尝试构建一个迭代器,它产生对Vec的引用。我会尝试解释我的理由,以了解我的缺陷。

我的第一次尝试是让迭代器拥有对象:

pub struct VecIter<T> {
    x: Vec<T>,
}

然而,根据Iterator returning items by reference, lifetime issue,这不起作用。上面的答案有两个建议:不要返回引用,或者引用该对象。

引用答案:

  

对于您具体的,可能是简单的例子,您应该停下来   产生引用,或改变它,以便你的迭代器对象不会   包含你迭代的数据 - 让它只包含一个   参考它,例如&amp;'a [T]甚至像物品&lt;'a,T&gt;。

我想实现第二个选项:即,通过让迭代器包含引用来返回引用。

我已将代码缩减为最简单的版本,我无法编译:

pub struct VecIter<'a, T> where T: 'a {
    x: &'a mut Vec<T>,
}

impl<'a, T> VecIter<'a, T> {
    fn next_(&'a mut self) -> Option<&'a Vec<T>> {
        // do something to modify self.x
        Some(self.x)
    }
}

pub fn main() {
    let mut vec_i = VecIter{x: &mut vec![100,200,300]};
    while let Some(x) = vec_i.next_() {
        // ...
    }
}

我希望上面的代码能够正常工作,因为每个可变的借用只存在于循环体内。所以我的想法是借用循环体的引用,在循环中使用它,并在循环结束时结束借用。

是否可以构建这样的迭代器?即,构建一个迭代器,该迭代器产生对它在next()中修改的对象的引用?

修改

在Matthieu M的评论中,有人建议我为此工作:

  

删除'a,以便next_(&'a mut self)变为next_(&mut self)

也许我理解错误,但我尝试了这个,我得到了以下编译错误。为了避免混淆,这里是我尝试的代码(playground):

<anon>:8:14: 8:20 error: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements [E0495]
<anon>:8         Some(self.x)
                      ^~~~~~
<anon>:6:5: 9:6 help: consider using an explicit lifetime parameter as shown: fn next_(&'a mut self) -> Option<&'a Vec<T>>
<anon>:6     fn next_(&mut self) -> Option<&'a Vec<T>> {
<anon>:7         // do something to modify self.x
<anon>:8         Some(self.x)
<anon>:9     }
error: aborting due to previous error
playpen: application terminated with error code 101

1 个答案:

答案 0 :(得分:1)

以下是您的next_()方法的修改,似乎有效:

fn next_<'b>(&'b mut self) -> Option<&'b Vec<T>>
where 'a: 'b { ... }

'b参数将被省略(lifetime elision),因此也可以这样做:

fn next_(&mut self) -> Option<&Vec<T>> { ... }

selfself.x的生命周期不同。 我在找出这个不起作用的确切原因时遇到了一些麻烦,但一般来说,你不需要写&'x self,如果你从来没有'x永远不是self类型的参数。

编辑:好的,我现在明白了。我一直忽略self.x可变借用Vec的事实,但您尝试返回不可变引用它。如果self.x未标记为mut,则您可以返回Some(self.x)并将其复制。但是你不能复制一个可变引用,所以它必须重新借用。此外,重新借用(不可变)引用的存在将导致无法调用&mut self方法或销毁self直到引用被销毁,因此self必须比新借用更长。这就是为什么你无法返回&'a Vec<T>:如果可以的话,就不可能销毁self