这是一个简单的人工示例来说明问题:
fn sum_slice(v: &[i32]) -> i32 {
v.iter().sum()
}
fn sum_previous(v: &mut [i32]) {
for (i, val) in v.iter_mut().enumerate() {
*val = sum_slice(&v[0..i]);
}
}
fn main() {
let mut v = vec![1,1,1,1,1,1,1];
sum_previous(&mut v);
println!("{:?}", v);
}
理想情况是,sum_previous
将采用提供的切片,并用先前元素的总和替换每个元素。
但是这会产生错误:
error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as
mutable
--> src/main.rs:7:27
|
6 | for (i, val) in v.iter_mut().enumerate() {
| ------------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
7 | *val = sum_slice(&v[0..i]);
| ^ immutable borrow occurs here
我了解Rust限制我们只能使用一个可变引用并且不能同时不可变的问题。我还可以提供不同的解决方案,例如使用另一个向量存储结果,但是问题不是如何解决它,而是这里可接受的模式是什么?
FWIW,最初的问题是蜂窝自动机的实现,其中要处理的网格和要根据其邻居更新的每个单元。在那种情况下,网格是可变地借用的,而用于计算更新的函数期望一个不变的引用。
您可以使用split_at_mut
:
split_at_mut
(fn sum_previous(v: &mut [i32]) {
for i in 1..v.len() {
let (head, tail) = v.split_at_mut(i);
tail[0] = sum_slice(head);
}
}
)