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

标签 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() 调用中的不可变借用会如何干扰更早创建迭代器,即使迭代器确实会改变原始对象。

您能否解释一下这里发生了什么以及如何解决它?

最佳答案

这可能是错误 #8372由当前 for 的最低可行实现引起。它被实现为一个宏,使得

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()),则 it.view_creator().test_something()可以工作(使用手动解包的 for 循环)。

(FWIW,有一个特征采用 self 并在 &mut Thing 上实现它,而不是采用 &mut self 并直接在 Thing 上实现它,这有点奇怪;尽管有有时有很好的理由。)

关于pointers - 在迭代器上的 `for` 循环内的结构上使用其他方法,这可以改变该结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20906378/

相关文章:

c++ - 使用 memcpy 将 1KB 字节数组复制到单个变量。寻找更聪明的方法

c++ - 我可以将迭代器递增一个整数吗?

C++ 自定义迭代器和范围问题

rust - 迭代器循环中对容器对象的可变引用

c++ - 二维数组到指针

c - 为什么 malloc 在这里返回 NULL?

c - 为什么我得到这样一个数组的长度?

c++ - 如何确保函数模板的参数是随机访问迭代器?

rust - 类型名称 `int` 未定义或不在范围内

rust - 我可以有一个泛型类型绑定(bind),要求该类型是一个特征吗?