Как использовать итераторы в рекурсивных вызовах, изменяющих последовательность данных? - PullRequest
0 голосов
/ 13 января 2019

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? Есть ли способ сделать это с помощью итераторов?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...