rust - 递归闭包作为函数参数 “cannot infer an appropriate lifetime due to conflicting requirements”

标签 rust

这个问题比Closure as function parameter “cannot infer an appropriate lifetime due to conflicting requirements”复杂.

有一个将环境变量移入其中的递归闭包。

下面的代码有效,tool是函数式编程的有用函数包,包括 making recursive closure :

extern crate tool;
use tool::prelude::*;
use std::cell::Cell;

fn main() {
    let a = Cell::new(false);

    let fib = fix(move |f, x| {
        a.set(true);
        if x == 0 || x == 1 {
            x
        } else {
            // `f` is `fib`
            f(x - 1) + f(x - 2)
        }
    });

    println!("{}", fib(10));
}

我想知道是否可以将该闭包传递给一个函数,然后在该闭包中调用该函数,下面的代码会抛出错误。

extern crate tool;
use tool::prelude::*;
use std::cell::RefCell;

fn main() {
    let a = RefCell::new(false);

    let fib = fix(move |f, x| {
        *a.borrow_mut() = true;
        if x == 0 || x == 1 {
            x
        } else {
            // `f` is `fib`
            b(Box::new(f), x - 1) + f(x - 2)
        }
    });

    fn b (c: Box<Fn(u64) -> u64>, n: u64) -> u64 {
        c(n)
    }

    println!("{}", b(Box::new(fib), 10));
}
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:14:24
   |
14 |             b(Box::new(f), x - 1) + f(x - 2)
   |                        ^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 8:19... 
  --> src/main.rs:8:19
   |
8  |       let fib = fix(move |f, x| {
   |  ___________________^
9  | |         *a.borrow_mut() = true;
10 | |         if x == 0 || x == 1 {
11 | |             x
...  |
15 | |         }
16 | |     });
   | |_____^
   = note: ...so that the expression is assignable:
           expected &dyn std::ops::Fn(u64) -> u64
              found &dyn std::ops::Fn(u64) -> u64
   = note: but, the lifetime must be valid for the static lifetime...
   = note: ...so that the expression is assignable:
           expected std::boxed::Box<(dyn std::ops::Fn(u64) -> u64 + 'static)>
              found std::boxed::Box<dyn std::ops::Fn(u64) -> u64>

最佳答案

看起来你在这里混合了几个概念。首先,您必须了解它们之间的区别:

  1. fn(A) -> B
  2. impl Fn(A) -> BT: Fn(A) -> B
  3. &dyn Fn(A) -> B
  4. Box<dyn Fn(A) -> B>

数字 1 是指向函数的指针类型,就像在 C 中一样。

Number 2 是实现function 特征的泛型类型 Fn ,这是一种可调用的类型。

数字 3 是对可调用对象的动态引用(dyn 关键字是可选的)。

数字 4 是一个 trait 对象,它是一个已删除实际类型的盒装可调用对象。

现在看 tool::fix 的定义:

pub fn fix<A, B, F>(f: F) -> impl Fn(A) -> B 
where
    F: Fn(&Fn(A) -> B, A) -> B, 

从中你可以看到 fix使用数字 2 作为 f参数,但 A 的编号为 3 f 的参数.此外,它返回数字 2。

这里棘手的部分是 f是一个以函数作为参数的函数。 f本身可以是实现 Fn 的任何一种, 但该函数的第一个参数必须是 &dyn Fn亲切。

您最初的错误来自于尝试装箱 &dyn Fn(A) -> B , 但你不能一般地这样做,因为这样的值可能包含引用,并且 Box需要 'static类型。

但考虑到所有这些,您可以在不使用 Box 的情况下仔细编写您的函数。 ,所以你的问题就消失了,结果更好(playground):

fn main() {
    fn wrap (wrap_fn: impl Fn(&dyn Fn(u64) -> u64, u64) -> u64) -> impl Fn(u64) -> u64 {
        let a = RefCell::new(false);

        let fib = fix(move |f, x| {
            *a.borrow_mut() = true;
            if x == 0 || x == 1 {
                x
            } else {
                // `f` is `fib`
                wrap_fn(f, x - 1) + wrap_fn(f, x - 2)
            }
        });  

        fib
    }

    fn b (c: &dyn Fn(u64) -> u64, n: u64) -> u64 {
        c(n)
    }

    println!("{}", (wrap(b))(10));
}

关于rust - 递归闭包作为函数参数 “cannot infer an appropriate lifetime due to conflicting requirements”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52619274/

相关文章:

rust - 我需要推送 (Vec) 包含的结构成员,他也是一个结构

hashmap - 为什么 HashMap 需要加密安全的哈希函数?

rust - 访问 par_iter_mut 内集合中不同索引的字段

rust - Rust实现Arc <Bar>到Arc <dyn Foo>的特征

rust - AsyncRead中Timeout不会超时

rust - 特征边界 `std::io::Write + ' static: std::marker::Sized` 不满足,当传递闭包时

rust - Rust泛型: expected type parameter,找到&T

tcp - 如何确定我是否需要来自 Rust io::Error 的新 TCP 连接?

gtk - GTK 中的 new_from_file()——我总是需要那个 "glade"文件吗?我可以嵌入它吗?

rust - 如何在条件下反转 Range?