我遇到的是potentially a compiler bug。但是,我不能很好地理解这个问题,以便将提议的解决方案移植到我自己的代码中。这是我的代码的简化版本:
struct Node {
pub children: Vec<Node>,
}
fn map_nodes<F, R>(f: F, n: &Node) -> Vec<R>
where
F: Fn(&Node) -> R,
{
let mut v: Vec<R> = Vec::new();
v.push(f(n));
v.extend(n.children.iter().flat_map(|child| map_nodes(&f, &child)));
v
}
fn main() {
let node = Node {
children: vec![Node { children: vec![] }, Node { children: vec![] }],
};
println!("Node lengths: {:?}", map_nodes(|n| n.children.len(), &node));
}
具体而言,此代码的错误是:
error[E0275]: overflow evaluating the requirement `[closure@src/main.rs:22:46: 22:66]: std::ops::Fn<(&Node,)>`
|
= help: consider adding a `#![recursion_limit="128"]` attribute to your crate
= note: required because of the requirements on the impl of `std::ops::Fn<(&Node,)>` for `&[closure@src/main.rs:22:46: 22:66]`
= note: required because of the requirements on the impl of `std::ops::Fn<(&Node,)>` for `&&[closure@src/main.rs:22:46: 22:66]`
# ... this continues for many lines ...
答案 0 :(得分:9)
问题是不兼容性(我将展示如何解决)在唯一闭包类型之间,在编译Rust时如何实例化泛型,以及递归使用闭包。
fn map_nodes<F, R>(f: F, n: &Node) -> Vec<R>
where
F: Fn(&Node) -> R,
每个递归调用都会实例化此函数的新版本,并为F
插入新类型。在这种情况下,map_nodes
会收到F
并传递&F
,并会创建一系列需要编译的无限新map_nodes
专精。
您可以做的是使用对Fn
特征对象的引用来使用具体的闭包类型:
fn map_nodes<R>(f: &Fn(&Node) -> R, n: &Node) -> Vec<R>
这需要在使用闭包的lambda表达式之前插入&
:map_nodes(&|n| n.children.len(), &node)
。
如果您不想为公共API带来这种差异,那么您可以使用内部包装器代替递归功能:
fn map_nodes<F, R>(f: F, n: &Node) -> Vec<R>
where
F: Fn(&Node) -> R,
{
fn map_nodes_inner<R>(f: &Fn(&Node) -> R, n: &Node) -> Vec<R> {
let mut v: Vec<R> = Vec::new();
v.push(f(n));
v.extend(n.children.iter().flat_map(|child| map_nodes_inner(f, &child)));
v
}
map_nodes_inner(&f, n)
}
答案 1 :(得分:6)
我没有声称完全理解这个问题,但这似乎是解决类型参数的问题。例如,F
对应的是什么?在第一级,它是关闭。在下一个级别,它是对该闭包的引用。在下一个级别,它是对闭包引用的引用。
我的猜测是因为内联而发生这种情况,基本上它已经达到无限递归。
您可以通过将引用传递给闭包来修复它:
struct Node {
pub children: Vec<Node>,
}
fn map_nodes<F, R>(f: &F, n: &Node) -> Vec<R>
where
F: Fn(&Node) -> R,
{
let mut v = Vec::new();
let z: R = f(n);
v.push(z);
v.extend(n.children.iter().flat_map(|child| map_nodes(f, &child)));
v
}
fn main() {
let node = Node {
children: vec![Node { children: vec![] }, Node { children: vec![] }],
};
println!(
"Node lengths: {:?}",
map_nodes(&|n| n.children.len(), &node)
);
}