This piece of code does not compile:
pub struct Test<T> {
Test: &'static fn(T) -> T,
}
This is a reduced snippet from something more complex.
I get "the parameter type T may not live long enough" and a hint to add T: 'static, but I do not see exactly why the lifetime of fn(T) -> T should be affected by the lifetime of T.
Why do I get this error and can I workaround it to avoid requiring T: 'static?
What you probably want is:
pub struct Test<'a, T> {
f: &'a fn(T) -> T,
}
To answer why the compiler doesn't allow the 'static reference, having a &'static fn(T) -> T for non-static T doesn't really make sense:
fn make_static_fn<T>(_: T) -> &'static fn(T) -> T { todo!() }
let f: &'static fn(_) -> _;
// Assume the following block compiles, which it would if &'static fn(T) -> T were allowed
{
let a = 42;
f = make_static_fn(&a); // T = &'a i32
}
// This is fine, as 0 is const, so &0 is a static reference, and 'static: '_
// which includes 'a, so &0 coerces to &'a i32 = T
let a_ref = (f)(&0);
// From the compiler's point of view, a_ref is a reference with lifetime 'a,
// a lifetime that already expired. The existence of a_ref requires that the
// `a` variable from the inner block earlier is still borrowed.
Playground
For a more concrete example of how this could lead to UB, the following uses a dyn Fn() -> T rather than a function pointer.
// This function is totally valid
fn make_static_fn<T: Copy>(t: T) -> &'static dyn Fn() -> T {
Box::leak(Box::new(move || { t }))
}
fn main() {
let f: &'static dyn Fn() -> _;
// Assume the following block compiles, which it would if &'static Fn() -> T were allowed
{
let a = 42;
// f creates copies of &a
f = make_static_fn(&a); // T = &'a i32
}
let a_ref = (f)();
// If the compiler allowed this, a_ref would contain a reference to a!
}
Playground
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With