这个问题比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>
最佳答案
看起来你在这里混合了几个概念。首先,您必须了解它们之间的区别:
-
fn(A) -> B
-
impl Fn(A) -> B
或T: Fn(A) -> B
-
&dyn Fn(A) -> B
-
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/