'Global function pointer to a method errors "mismatched types"
I want to make a global function pointer pointing to a class method, so I did something like the following minimal reproducible example:
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);
}
But rustc
gives me this error:
$ 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`.
What is this error trying to say? How can I fix it?
Solution 1:[1]
Function pointers in Rust can have early-bound and late-bound lifetime parameters. An early-bound lifetime parameter needs to be specified at the time the function pointer is created. A late-bound lifetime parameter is only specified when the function the pointer points to is called, and it can be different each time the function is called.
The function pointer type FooFn
has two late-bound lifetime parameters. As spelled out in the error message, it's definition is equivalent to
let FooFn = for<'r, 's> fn(&'r Foo<'s>);
The type of Foo::foo
is different, though. An associated function can only be looked up once the type it is associated with is fully specified. In other words, all lifetime parameters of the self type need to be early-bound. This means Foo::foo
has one early-bound and one late-bound lifetime parameter. The lifetime parameter of Foo
gets fixed at the time the function pointer is created, and the function pointer can only be called for that specific lifetime. The compiler denotes this yet-to-be-determined lifetime as '_
in the error message. (In this context, '_
would later be inferred to be 'static
, since it's the only fixed lifetime that makes sense here, but that's not really relevant for this question.)
There are a few ways to work around this. One way is to make foo()
a free function:
fn foo(foo: &Foo) {
println!("{}", foo.data);
}
Another way is to wrap Foo::foo
in a trivial closure:
const FUNC: FooFn = |f| Foo::foo(f);
This way, the function we reference is no longer an associated function, and all lifetime parameters can be late-bound.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | marc_s |