recursion - 在 Rust 中返回一个递归闭包

标签 recursion reference rust closures lifetime

我有以下高阶函数

fn ensure_tonicty(tone_fn: &fn(&f64, &f64) -> bool) -> impl Fn(&Vec<f64>) -> bool {
    return |floats: &Vec<f64>| -> bool {
        let first = floats.first().unwrap();
        let rest = &floats[1..];
        fn f(tone_fn: &fn(&f64, &f64) -> bool, prev: &f64, xs: &[f64]) -> bool {
            match xs.first() {
                Some(x) => tone_fn(prev, x) && f(tone_fn, x, &xs[1..]),
                None => true,
            }
        };
        return f(tone_fn, first, rest);
    };
}

我的目标是返回这个 lambda。不过,我不知道如何在这里有效地使用 tone_fn

上面的代码出错了:

error[E0621]: explicit lifetime required in the type of `tone_fn`
 --> src/lib.rs:1:56
  |
1 | fn ensure_tonicty(tone_fn: &fn(&f64, &f64) -> bool) -> impl Fn(&Vec<f64>) -> bool {
  |                            -----------------------     ^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
  |                            |
  |                            help: add explicit lifetime `'static` to the type of `tone_fn`: `&'static for<'r, 's> fn(&'r f64, &'s f64) -> bool`

如果我尝试包括生命周期,我不确定如何键入 impl Fn,并包括生命周期

// where do I write `'a`?
fn ensure_tonicty<'a>(tone_fn: &'a fn(&f64, &f64) -> bool) -> impl Fn(&Vec<f64>) -> bool {

我可以把它写成一个宏并通过它,但我很好奇是否有一种方法可以在不走宏路线的情况下做到这一点。

最佳答案

您正在使用很多 引用资料,这似乎不是必需的,并且让您更难弄清楚这一切:

  1. A fn 已经是一个函数指针,因此您可以按值传递它们,而不是使用另一层引用。这更容易,因为函数指针是 'static .
  2. 所有这些 &f64 s 是不可变的,因此可以替换为 f64不改变逻辑。这应该与使用引用的速度相同(或者可能更快)。

一旦你这样做了,你将没有太多引用,并且会更清楚是什么导致了问题:

fn ensure_tonicty(tone_fn: fn(f64, f64) -> bool) -> impl Fn(&Vec<f64>) -> bool {
    |floats: &Vec<f64>| -> bool {
        let first = *floats.first().unwrap();
        let rest = &floats[1..];
        fn f(tone_fn: fn(f64, f64) -> bool, prev: f64, xs: &[f64]) -> bool {
            match xs.first() {
                Some(&x) => tone_fn(prev, x) && f(tone_fn, x, &xs[1..]),
                None => true,
            }
        };
        f(tone_fn, first, rest);
    };
}

现在,错误是:

error[E0373]: closure may outlive the current function, but it borrows `tone_fn`, which is owned by the current function
  --> src/lib.rs:2:12
   |
2  |     return |floats: &Vec<f64>| -> bool {
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ may outlive borrowed value `tone_fn`
...
11 |         return f(tone_fn, first, rest);
   |                  ------- `tone_fn` is borrowed here
   |
note: closure is returned here
  --> src/lib.rs:2:12
   |
2  |       return |floats: &Vec<f64>| -> bool {
   |  ____________^
3  | |         let first = *floats.first().unwrap();
4  | |         let rest = &floats[1..];
5  | |         fn f(tone_fn: fn(f64, f64) -> bool, prev: f64, xs: &[f64]) -> bool {
...  |
11 | |         return f(tone_fn, first, rest);
12 | |     };
   | |_____^
help: to force the closure to take ownership of `tone_fn` (and any other referenced variables), use the `move` keyword
   |
2  |     return move |floats: &Vec<f64>| -> bool {
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

help部分告诉您如何修复它:关闭 move它的环境。结果是:

fn ensure_tonicty(tone_fn: fn(f64, f64) -> bool) -> impl Fn(&[f64]) -> bool {
    move |floats: &[f64]| -> bool {
        let first = floats[0];
        let rest = &floats[1..];
        fn f(tone_fn: fn(f64, f64) -> bool, prev: f64, xs: &[f64]) -> bool {
            match xs.first() {
                Some(&x) => tone_fn(prev, x) && f(tone_fn, x, &xs[1..]),
                None => true,
            }
        };
        f(tone_fn, first, rest)
    }
}

如果您从另一个函数返回一个闭包,您几乎总是需要这个关键字。否则,闭包中提到的任何变量都将引用函数结束时将超出范围的值。使用 move关键字会移动这些值,因此它们会随闭包移动。


另请注意我所做的其他更改,以使代码更加地道:

  1. 使用表达式代替 return关键字。
  2. 使用&[f64]而不是 &Vec<f64>在函数参数中(参见 Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument? )。

关于recursion - 在 Rust 中返回一个递归闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55748962/

相关文章:

java - 使用 toString 递归打印 Node 及其后继者

java - 关于Java中数组的引用

c++ - 比较 map 对象及其引用 C++

rust - 如何将动态数量的类型参数传递给函数?

递归后返回 None 的 Python 函数

javascript - 带有回调的递归函数 JS

php - 使用递归函数解码字谜不会给出预期的输出

c - 使用 Code::Blocks IDE 在 C 中出现 undefined reference 错误

rust - 我可以在与 gen_range 的模式匹配中避免 `_` 吗?

rust - 交叉编译 [no_std] 代码 - 未找到 libcore 和 compiler_builtins