指向方法错误的全局函数指针 "mismatched types"

Global function pointer to a method errors "mismatched types"

我想创建一个指向 class 方法的全局函数指针,所以我做了类似以下最小可重现示例的操作:

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);
}

Rust Playground

但是 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`.

这个错误想表达什么意思?我该如何解决?

Rust 中的函数指针可以有 early-boundlate-bound 生命周期参数。在创建函数指针时需要指定一个 early-bound 生命周期参数。 late-bound 生命周期参数仅在指针指向的函数被 调用时指定 ,并且每次调用函数时都可以不同。

函数指针类型 FooFn 有两个 late-bound 生存期参数。如错误消息中所述,它的定义等同于

let FooFn = for<'r, 's> fn(&'r Foo<'s>);

不过 Foo::foo 的类型不同。只有在完全指定关联的类型后才能查找关联函数。也就是说,self类型的所有生命周期参数都需要是early-bound。这意味着 Foo::foo 有一个 early-bound 和一个 late-bound 生命周期参数。 Foo 的生命周期参数在创建函数指针时固定,函数指针只能在该特定生命周期内调用。编译器在错误消息中将此 yet-to-be-determined 生命周期表示为 '_。 (在这种情况下,'_later be inferred to be 'static,因为它是唯一在这里有意义的固定生命周期,但这与这个问题并不相关。)

有几种方法可以解决这个问题。一种方法是使 foo() 成为一个自由函数:

fn foo(foo: &Foo) {
    println!("{}", foo.data);
}

另一种方法是将 Foo::foo 包装在一个简单的闭包中:

const FUNC: FooFn = |f| Foo::foo(f);

这样我们引用的函数就不再是关联函数了,所有生命周期参数都可以late-bound.