如何在相同元素的另一个可变迭代中迭代可变元素?
How to iterate over mutable elements inside another mutable iteration over the same elements?
我有一个 Element
数组,我想遍历它来做一些事情,然后遍历循环内的所有 Element
来做一些事情。元素之间存在关系,因此我想遍历所有其他元素以检查某些内容。由于某些原因,元素是可变引用。它有点宽泛,但我试图笼统(也许我不应该)。
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
我知道它是 a normal behavior in Rust,但是避免此错误的推荐方法是什么?我应该先复制元素吗?忘记循环并以不同的方式迭代?了解代码设计?
有没有 Rusty 方法可以做到这一点?
你不能这样做,句号。 The rules of references 状态,强调我的:
At any given time, you can have either one mutable reference or any number of immutable references
在第一次迭代中,您试图获得对数组中第一个元素的 两个 可变引用。这必须是不允许的。
您的方法根本不需要可变引用 (fn do_something(&self, e: &Element) {}
),所以最简单的方法就是切换到不可变迭代器:
for e in &elements {
for f in &elements {
e.doSomething(f);
}
}
如果你确实需要在循环内执行变异,你也需要切换到interior mutability。这将规则的执行从编译时间转移到 运行 时间,因此当您尝试同时获取对同一项目的两个可变引用时,您现在会感到恐慌:
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);
}
}
}
您可以使用索引迭代而不是使用迭代器进行迭代。然后,在内循环中,您可以使用 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);
}
}
我有一个 Element
数组,我想遍历它来做一些事情,然后遍历循环内的所有 Element
来做一些事情。元素之间存在关系,因此我想遍历所有其他元素以检查某些内容。由于某些原因,元素是可变引用。它有点宽泛,但我试图笼统(也许我不应该)。
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
我知道它是 a normal behavior in Rust,但是避免此错误的推荐方法是什么?我应该先复制元素吗?忘记循环并以不同的方式迭代?了解代码设计?
有没有 Rusty 方法可以做到这一点?
你不能这样做,句号。 The rules of references 状态,强调我的:
At any given time, you can have either one mutable reference or any number of immutable references
在第一次迭代中,您试图获得对数组中第一个元素的 两个 可变引用。这必须是不允许的。
您的方法根本不需要可变引用 (fn do_something(&self, e: &Element) {}
),所以最简单的方法就是切换到不可变迭代器:
for e in &elements {
for f in &elements {
e.doSomething(f);
}
}
如果你确实需要在循环内执行变异,你也需要切换到interior mutability。这将规则的执行从编译时间转移到 运行 时间,因此当您尝试同时获取对同一项目的两个可变引用时,您现在会感到恐慌:
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);
}
}
}
您可以使用索引迭代而不是使用迭代器进行迭代。然后,在内循环中,您可以使用 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);
}
}