“溢出评估需求”是什么意思,我该如何解决?

时间:2015-07-02 23:50:29

标签: recursion rust

我遇到的是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 ...

2 个答案:

答案 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)
    );
}