Given a struct with a lifetime parameter (essential: the problem disappears if the struct doesn't have a lifetime parameter):
struct Foo<'a> {
datum: &'a u8,
}
and a method on that struct that returns a value derived from &self
, but that doesn't refer to &self
and so (AIUI) should be able to outlive it:
impl<'a> Foo<'a> {
pub fn foo(&self) -> u8 {
self.datum + 1
}
}
I want to write a generic function that gets a Foo
from somewhere and then applies a closure to it, returning the closure's return value:
fn apply_closure<T, F>(f: F) -> T
where
F: for<'r> FnOnce(&'r Foo) -> T,
{
let datum = 0u8;
let foo = Foo { datum: &datum };
f(&foo)
}
The Foo
does not outlive the function (in my real-life code I'm creating it within apply_closure
by talking to some hardware), but the closure return value can outlive that Foo
.
This compiles:
fn good() {
apply_closure(|f| f.foo());
}
but this does not:
fn bad() {
apply_closure(Foo::foo);
}
which I do not understand. I also don't understand the compiler's error message, particularly where the "expected" and "found" types appear to be identical:
error[E0308]: mismatched types
--> lifetime.rs:51:5
|
51 | apply_closure(Foo::foo);
| ^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected type `for<'r> <for<'r> fn(&'r Foo<'_>) -> u8 {Foo::<'_>::foo} as FnOnce<(&'r Foo<'_>,)>>`
found type `for<'r> <for<'r> fn(&'r Foo<'_>) -> u8 {Foo::<'_>::foo} as FnOnce<(&'r Foo<'_>,)>>`
note: the lifetime requirement is introduced here
--> lifetime.rs:18:36
|
18 | F: for <'r> FnOnce(&'r Foo) -> T,
| ^
I think that I need to put some sort of lifetime specifier T
to say that it can outlive the &Foo
passed to the closure, but not sure. I've tried various permutations but haven't made the apply(Foo::foo)
version compile.
Many thanks.