gpt4 book ai didi

recursion - 使用 impl trait 返回递归迭代器时溢出评估需求

转载 作者:行者123 更新时间:2023-11-29 08:29:17 26 4
gpt4 key购买 nike

我正在尝试对 Rust 中的树结构进行深度优先迭代。我以为我有一个非常好的简洁解决方案,但我无法编译它。从概念上讲,它非常简单:遍历子节点,获取每个子节点的深度优先迭代器,展平它们,并将当前节点的元数据迭代器链接到它。

#[derive(Debug, Eq, PartialEq)]
struct Node {
metadata: Vec<i64>,
children: Vec<Box<Node>>,
}

impl Node {
fn depth_first_metadata_iter(&self) -> impl Iterator<Item = &i64> + '_ {
self.children
.iter()
.map(|child| child.depth_first_metadata_iter())
.flatten()
.chain(self.metadata.iter())
}
}

fn main() {
let tree = Node {
metadata: vec![1, 2, 3],
children: vec![
Box::new(Node {
metadata: vec![4, 5],
children: vec![],
}),
Box::new(Node {
metadata: vec![6, 7],
children: vec![],
}),
],
};
println!(
"{:?}",
tree.depth_first_metadata_iter().collect::<Vec<&i64>>()
);
}

但是,当我编译它时,出现以下错误:

error[E0275]: overflow evaluating the requirement `impl std::iter::Iterator`
|
= help: consider adding a `#![recursion_limit="128"]` attribute to your crate

(您可以在 playground 上自行查看。)

这将是一个错误是有道理的,因为我在 depth_first_metadata_iter 中进行递归调用,它返回嵌套的迭代器,但如果像这样的代码无需实现就可以工作,那就太好了自定义迭代器。

我看到的 E0275 错误的所有其他解决方案(例如 thisthisthis )似乎都涉及战略性地在某处放置类型注释 - 类似这样的可能在这里,还是我在尝试一些“不可能”的事情?

最佳答案

if something like this code could work

取决于你的“喜欢”程度。这很相似,可以工作,并且不需要自定义迭代器;从而满足您的所有要求:

fn depth_first_metadata_iter(&self) -> Box<Iterator<Item = &i64> + '_> {
Box::new({
self.children
.iter()
.flat_map(|child| child.depth_first_metadata_iter())
.chain(self.metadata.iter())
})
}

本质上,这与中所示的问题相同

让自己站在编译器的角度思考一会儿。您的原始代码说“我将返回一个具体的迭代器类型,但我不会说出确切的类型”。编译器仍然必须能够找出该类型,所以让我们成为编译器吧:

let a = self.children.iter();
// std::slice::Iter<'_, Box<Node>>

let cls = |child| child.depth_first_metadata_iter();
// Fn(&Box<Node>) -> ?X?

let b = a.flat_map(cls);
// FlatMap<Iter<'_, Box<Node>>, ?X?, Fn(&Box<Node>) -> ?X?>

let d = self.metadata.iter();
// std::slice::Iter<'_, i64>

b.chain(d);
// Chain<FlatMap<Iter<'_, Box<Node>>, ?X?, Fn(&Box<Node>) -> ?X?>, Iter<'_, i64>>

这个最终结果就是返回值,所以我们有我们的等式:

Chain<FlatMap<Iter<'_, Box<Node>>, ?X?, Fn(&Box<Node>) -> ?X?>, Iter<'_, i64>> === ?X?

AFAIK,不可能执行类型级代数来求解 ?X?,因此会出现错误。

将返回类型更改为装箱特征对象会短路所有需要的逻辑并强制使用特定的具体类型。

strategically placing a type annotation somewhere

我不认为这是事实。如果是这样,那将意味着代数可解的,但编译器不够聪明,无法解决它。虽然这在其他情况下无疑是正确的,但我不认为它在这里。


我不认为这是一个很好的解决方案,因为这将涉及大量微小的分配。我假设(但尚未测试)使用堆栈数据结构的自定义迭代器会更有效率。

中间立场是建立整个节点集:

impl Node {
fn depth_first_metadata_iter(&self) -> impl Iterator<Item = &i64> + '_ {
self.x().into_iter()
}

fn x(&self) -> Vec<&i64> {
fn x_inner<'a>(node: &'a Node, v: &mut Vec<&'a i64>) {
for c in &node.children {
x_inner(c, v)
}
v.extend(&node.metadata);
}

let mut v = Vec::new();
x_inner(self, &mut v);
v
}
}

关于recursion - 使用 impl trait 返回递归迭代器时溢出评估需求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53989219/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com