TL / DR
У меня есть рекурсивный алгоритм, где каждый вызов хочет изменить записи в итерируемой структуре данных (a 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? Есть ли способ сделать это с помощью итераторов?