How to iterate over mutable elements inside another mutable iteration over the same elements?

天涯浪子 提交于 2019-12-05 18:07:21
oli_obk

You can use indexed iteration instead of iterating with iterators. Then, inside the inner loop, you can use split_at_mut to obtain two mutable references into the same slice.

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);
    }
}

You cannot do this, period. The rules of references state, emphasis mine:

At any given time, you can have either one mutable reference or any number of immutable references

On the very first iteration, you are trying to get two mutable references to the first element in the array. This must be disallowed.


Your method doesn't require mutable references at all (fn do_something(&self, e: &Element) {}), so the simplest thing is to just switch to immutable iterators:

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

If you truly do need to perform mutation inside the loop, you will also need to switch to interior mutability. This shifts the enforcement of the rules from compile time to run time, so you will now get a panic when you try to get two mutable references to the same item at the same time:

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);
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!