如何在另一个元素上迭代另一个可变迭代内的可变元素



我有一个 Element s的数组,我想迭代它做一些事情,然后在循环内部的所有 Element s上迭代以做某事。元素之间存在关系,因此我想迭代所有其他元素以检查某些内容。由于原因,这些元素是可变的参考。这有点广泛,但是我想成为一般(也许我不应该)。

struct Element;
impl Element {
    fn do_something(&self, _e: &Element) {}
}
fn main() {
    let mut elements = [Element, Element, Element, Element];
    for e in &mut elements {
        // Do stuff...
        for f in &mut elements {
            e.do_something(f);
        }
    }
}

正如预期的,我得到了这个错误:

error[E0499]: cannot borrow `elements` as mutable more than once at a time
  --> src/main.rs:13:18
   |
10 |     for e in &mut elements {
   |              -------------
   |              |
   |              first mutable borrow occurs here
   |              first borrow later used here
...
13 |         for f in &mut elements {
   |                  ^^^^^^^^^^^^^ second mutable borrow occurs here

我知道这是Rust的正常行为,但是避免此错误的推荐方法是什么?我应该先复制元素吗?忘记循环并以不同的方式进行迭代?了解代码设计?

有生锈的方法可以做到吗?

您可以使用索引迭代,而不是使用迭代器进行迭代。然后,在内部循环内,您可以使用split_at_mut在同一切片中获取两个可变的参考。

for i in 0..elements.len() {
    for j in 0..elements.len() {
        let (e, f) = if i < j {
            // `i` is in the left half
            let (left, right) = elements.split_at_mut(j);
            (&mut left[i], &mut right[0])
        } else if i == j {
            // cannot obtain two mutable references to the
            // same element
            continue;
        } else {
            // `i` is in the right half
            let (left, right) = elements.split_at_mut(i);
            (&mut right[0], &mut left[j])
        };
        e.do_something(f);
    }
}

您无法执行此操作。参考规则状态,重点是我的:

在任何给定时间,您都可以具有一个一个可变的参考或任何数量不变的参考

在第一次迭代中,您正在尝试获取两个对数组中第一个元素的可变引用。这必须不允许。


您的方法根本不需要可变的参考(fn do_something(&self, e: &Element) {}),因此最简单的是切换到不可变的迭代器:

for e in &elements {
    for f in &elements {
        e.doSomething(f);
    }
}

如果您确实需要在循环内执行突变,则还需要切换到内部可突变性。这将规则的执行从编译时间转变为运行时间,因此,当您尝试同时获得两个可变的参考时,您现在会感到恐慌:

use std::cell::RefCell;
struct Element;
impl Element {
    fn do_something(&mut self, _e: &mut Element) {}
}
fn main() {
    let mut elements = [
        RefCell::new(Element),
        RefCell::new(Element),
        RefCell::new(Element),
        RefCell::new(Element),
    ];
    for e in &elements {
        for f in &elements {
            // Note that this will panic as both `e` and `f` 
            // are the same value to start with
            let mut e = e.borrow_mut();
            let mut f = f.borrow_mut();
            e.do_something(&mut f);
        }
    }
}

最新更新