这个问题比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>
答案 0 :(得分:1)
您似乎在这里混几个概念。首先,您必须了解它们之间的区别:
fn(A) -> B
impl Fn(A) -> B
或T: Fn(A) -> B
&dyn Fn(A) -> B
Box<dyn Fn(A) -> B>
数字1是指向函数的指针的类型,就像在C语言中一样。
数字2是实现 function 特征Fn
的泛型类型,即可调用的类型。
数字3是对可调用对象的动态引用(dyn
关键字是可选的)。
数字4是一个特征对象,它是一个装箱的可调用对象,其真实类型已删除。
现在看看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
,而数字3使用A
参数。而且,它返回数字2。
这里最棘手的部分是f
是一个以函数为参数的函数。 f
本身可以是实现f
的任何类型,但是该函数的第一个参数必须为Fn
类型。
您的原始错误来自试图装箱&dyn Fn
的问题,但是您不能一般地这样做,因为这样的值可能包含引用,并且&dyn Fn(A) -> B
需要使用Box
类型。
但是考虑到所有这些,您可以不用使用'static
来仔细地编写函数,因此问题就消失了,结果更好了(playground):
Box