我想创建一个指向类方法的全局函数指针,所以我做了类似以下最小可重现示例的操作:
struct Foo<'a> {
data: &'a str,
}
impl<'a> Foo<'a> {
pub fn foo(&self) {
println!("{}", self.data);
}
}
type FooFn = fn(&Foo);
const FUNC: FooFn = Foo::foo;
fn main() {
let data = String::from("hello");
let foo = Foo { data: &data };
FUNC(&foo);
}
Run Code Online (Sandbox Code Playgroud)
但rustc给了我这个错误:
$ rustc test.rs
error[E0308]: mismatched types
--> test.rs:13:21
|
13 | const FUNC: FooFn = Foo::foo;
| ^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'r, 's> fn(&'r Foo<'s>)`
found fn pointer `for<'r> fn(&'r Foo<'_>)`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
Run Code Online (Sandbox Code Playgroud)
这个错误想表达什么?我该如何修复它?
Rust 中的函数指针可以具有早期绑定和晚期绑定的生命周期参数。需要在创建函数指针时指定早期绑定生命周期参数。后期绑定生命周期参数仅在调用指针指向的函数时指定,并且每次调用该函数时该参数都可以不同。
函数指针类型FooFn有两个后期绑定生命周期参数。正如错误消息中所述,它的定义相当于
let FooFn = for<'r, 's> fn(&'r Foo<'s>);
Run Code Online (Sandbox Code Playgroud)
但类型Foo::foo不同。只有在完全指定关联函数的类型后,才能查找关联函数。换句话说,self 类型的所有生命周期参数都需要提前绑定。这意味着Foo::foo具有一个早期绑定和一个后期绑定生命周期参数。的生命周期参数Foo在创建函数指针时固定,并且只能在该特定生命周期内调用该函数指针。'_编译器在错误消息中表示了这个尚未确定的生命周期。(在这种情况下,稍后'_将被推断为'static,因为它是唯一在这里有意义的固定生命周期,但这与这个问题并不真正相关。)
有几种方法可以解决这个问题。一种方法是创建foo()一个自由函数:
fn foo(foo: &Foo) {
println!("{}", foo.data);
}
Run Code Online (Sandbox Code Playgroud)
另一种方法是封装Foo::foo一个简单的闭包:
const FUNC: FooFn = |f| Foo::foo(f);
Run Code Online (Sandbox Code Playgroud)
这样,我们引用的函数就不再是关联函数,并且所有生命周期参数都可以进行后期绑定。