在迭代器上的`for`循环内的结构上使用其他方法,可以改变这个结构

时间:2014-01-03 14:54:45

标签: pointers iterator rust

我在结构上有类似的方法:

impl<'a> SomeStructure<'a> {
    // I need &'a mut because the iterator may mutate SomeStructure
    fn iter<'a>(&'a mut self) -> SomeIterator<'a> {
        SomeIterator { object: self }
    }

    fn test_something(&self) -> bool {
        self.some_field < 0
    }

}

然后我想这样使用它们:

impl<'a> SomeTrait for &'a mut SomeStructure<'a> {
    fn do_something(self) {
        for e in self.iter() {
            ...
            if self.test_something() {
                break;
            }
        }
    }
}

但是,Rust不允许它(我修复了错误消息,因此他们引用了上面的示例代码):

io/convert_io.rs:119:17: 119:22 error: cannot borrow `*self` as immutable because it is also borrowed as mutable
io/convert_io.rs:119             if self.test_something() {
                                    ^~~~~
io/convert_io.rs:117:18: 117:23 note: previous borrow of `*self` occurs here
io/convert_io.rs:117         for e in self.iter() {
                                      ^~~~~

但是我没有看到self.test_something()调用中的不可变借用如何干扰先前创建迭代器,即使迭代器确实改变了原始对象。

您能解释一下这里发生了什么以及如何解决这个问题吗?

1 个答案:

答案 0 :(得分:2)

这可能是由当前for的最小工作实现引起的错误#8372。它被实现为宏,以便

for pattern in iterator { body }

扩展为(您可以通过运行rustc --pretty expanded foo.rs

来查看
{
    let it = &mut iterator;
    loop {
        match it.next() {
            None => break,
            Some(pattern) => { body }
        }
    }
}

问题是&mut iterator借用,当iterator在范围内时,会停止it直接使用。您通常可以通过自己手动编写扩展来解决此问题:

impl<'a> SomeTrait for &'a mut SomeStructure<'a> {
    fn do_something(self) {
        let mut it = self.iter();
        loop {
            match it.next() {
                None => break
                Some(e) => {
                    if self.test_something() {
                        break;
                    }
                }
            }
        }
    }
}

那说......如果self.iter()借用self(特别是如果test_something&mut self,那么在这种情况下实际上可能不起作用,因为编译器必须禁止变异或者迭代器可能无效)。

如果您要在.view_creator()的返回时添加self.iter()方法(假设您在self类型中引用self.iter()),则{{1}将工作(使用手动解包的for循环)。

(FWIW,有一个特点是有一个特点是it.view_creator().test_something()并在self上实施,而不是&mut Thing并在&mut self直接实施;虽然有有时是的充分理由。)