我有一个递归算法,其中每个调用都希望修改可迭代数据结构(Vec
)中的条目。如何使用迭代器在Rust中对此建模?
问题出现在另一个更复杂的环境中,我试图建立一个相当简单的例子来突出这个问题。我提到这一点是为了解释,如果您针对以下代码中要解决的特定问题(即子集总和)推荐完全不同的解决方案,那将无济于事。
考虑以下代码,并在任一选项前面都删除一个斜杠以将其注释掉。现在,选项1可以编译并按预期工作,但是选项2无法编译。
#[derive(Clone, Copy)]
struct Item {
in_subset: bool,
value: u32,
}
fn try_find_subset_with_sum(items: &mut Vec<Item>, goal: u32) -> bool {
let current = items
.iter()
.filter(|x| x.in_subset)
.fold(0, |sum, x| sum + x.value);
if current == goal {
true
} else {
if current > goal {
false
} else {
//* OPTION 1: ********************************
for k in 0..items.len() {
if !items[k].in_subset {
items[k].in_subset = true;
if try_find_subset_with_sum(items, goal) {
return true;
}
items[k].in_subset = false;
}
}
// *******************************************/
//* OPTION 2: ********************************
for x in items.iter_mut() {
if !x.in_subset {
x.in_subset = true;
if try_find_subset_with_sum(items, goal) {
return true;
} else {
x.in_subset = false
}
}
}
// *******************************************/
false
}
}
}
fn main() {
let tmp = vec![12, 9, 2, 1, 13, 46, 5, 5, 9];
let mut set: Vec<Item> = tmp
.into_iter()
.map(|x| Item {
in_subset: false,
value: x,
})
.collect();
if try_find_subset_with_sum(&mut set, 16) {
println!("found the following subset:");
for x in set {
if x.in_subset {
println!("{}", x.value);
}
}
}
}
选项2的错误消息指出:
error[E0499]: cannot borrow `*items` as mutable more than once at a time
--> src/main.rs:33:49
|
30 | for x in items.iter_mut() {
| ----------------
| |
| first mutable borrow occurs here
| first borrow used here, in later iteration of loop
...
33 | if try_find_subset_with_sum(items, goal) {
| ^^^^^ second mutable borrow occurs here
我了解编译器在告诉我什么。如果是人类,我会大喊大叫“只要在修改数据时就借用可恶的可迭代数据,然后在递归调用大声喊叫之前取回它!” 但我确实理解它可能无法做到这一点。
有比解决方案1更优雅的解决方案吗?有没有办法用迭代器做到这一点?