Я хочу создать рекурсивную функцию для обхода дерева в Rust. Функция всегда должна получать следующий элемент и итератор по ссылкам на элементы-предки.
Для итератора по элементам-предкам в принципе можно использовать методы chain
и once
. Рассмотрим следующий простой пример, где дерево является просто Vec (для целей этой демонстрации):
fn proceed<'a, I>(mut remaining: Vec<String>, ancestors: I)
where
I: Iterator<Item = &'a String> + Clone,
{
if let Some(next) = remaining.pop() {
let next_ancestors = ancestors.chain(std::iter::once(&next));
proceed(remaining, next_ancestors);
}
}
Это не может быть скомпилировано, потому что &next
имеет более короткий срок жизни, чем 'a
:
error[E0597]: `next` does not live long enough
--> src/lib.rs:6:62
|
1 | fn proceed<'a, I>(mut remaining: Vec<String>, ancestors: I)
| -- lifetime `'a` defined here
...
6 | let next_ancestors = ancestors.chain(std::iter::once(&next));
| --------------------------------^^^^^--
| | |
| | borrowed value does not live long enough
| argument requires that `next` is borrowed for `'a`
7 | proceed(remaining, next_ancestors);
8 | }
| - `next` dropped here while still borrowed
Я попытался преодолеть это, добавив явное второе время жизни 'b: 'a
и принудительно указав явную ссылку чем-то вроде let next_ref: &'b String = &next
, но это также приводит к (другому) сообщению об ошибке.
Одно из решений, которое я придумал, заключалось в том, чтобы позвонить map
следующим образом:
let next_ancestors = ancestors.map(|r| r).chain(std::iter::once(&next));
Как указывает @trentcl, этот на самом деле не решает проблему., поскольку компилятор застревает в бесконечном цикле при компиляции proceed
для всех вложенных Chain
, когда кто-то действительно пытается вызвать функцию.
proceed
в любом месте, компилятор попытается вычислить бесконечный тип (потому что для компиляцииproceed<I>
вы должны сначала скомпилироватьproceed<Chain<I, Once<String>>>
, а чтобы скомпилировать это, вы должны сначала скомпилироватьproceed<Chain<Chain<I, Once<String>>, Once<String>>>
и т.д. Теперь вы можете решить эту проблему с помощью динамической отправки ... - person trentcl   schedule 17.02.2020ancestors
нельзя разрешить заимствовать изremaining
, так как вы обходитеVec
деструктивно, поэтому вы не можете применить ту же стратегию для итерации по дереву по ссылке. Я не уверен, как лучше всего ответить на этот вопрос, потому что исправление текущей ошибки компилятора явно не решает проблему. Я настоятельно рекомендую вам сделать шаг назад и переоценить, как вы сюда попали; скорее всего найдется более простое решение. (Прочтите Изучите Rust с слишком большим количеством связанных списков, если у вас нет т уже.) - person trentcl   schedule 17.02.2020