How can I make a struct that is generic on a type which may be a reference, but does not have a lifetime parameter? The snippet below shows what I'm trying to do. There are two structs that both wrap Fn
. Foo
is 'static
because it doesn't have any non-'static
parameters. Bar
, when instantiated with &u32, u32
, will have exactly the same contents as Foo
. However, it won't be 'static
because of the &u32
parameter. It clearly could be 'static
; only the generic parameter stops it. There must be a way to do this, because Fn
does it. Is there a way to create a custom struct with higher-rank trait bounds?
use std::any::Any;
use std::marker::PhantomData;
struct Foo<F: Fn(&u32) -> u32 + 'static> {
f: Box<F>
}
impl<F> Foo<F>
where F: Fn(&u32) -> u32 + 'static
{
fn new(f: F) -> Self {
Foo{f: Box::new(f)}
}
}
struct Bar<I, O> {
f: Box<dyn Fn(I) -> O + 'static>,
_i: PhantomData<I>,
_o: PhantomData<O>,
}
impl<I, O> Bar<I, O>
{
fn new(f: Box<Fn(I) -> O>) -> Self {
Bar{f, _i: PhantomData, _o: PhantomData}
}
}
// That this compiles proves that Foo.f has no lifetime issues
fn foo_is_u64<F: Fn(&u32) -> u32 + 'static>(f: &Foo<F>) -> bool {
Any::is::<u64>(f)
}
// This fails to compile even though Bar.f is static.
// It fails just because of the I and O in Bar's type signature.
fn bar_is_u64<I, O>(b: &Bar<I, O>) -> bool {
Any::is::<u64>(b)
}
fn main() {
// Proves that There are 'static FnMut(&u32) -> u32 objects
let foo = Foo::new(|x| *x);
}
Errors:
Compiling playground v0.0.1 (/playground)
error[E0310]: the parameter type `O` may not live long enough
--> src/main.rs:37:20
|
36 | fn bar_is_u64<I, O>(b: &Bar<I, O>) -> bool {
| - help: consider adding an explicit lifetime bound `O: 'static`...
37 | Any::is::<u64>(b)
| ^
|
note: ...so that the type `Bar<I, O>` will meet its required lifetime bounds
--> src/main.rs:37:20
|
37 | Any::is::<u64>(b)
| ^
error[E0310]: the parameter type `I` may not live long enough
--> src/main.rs:37:20
|
36 | fn bar_is_u64<I, O>(b: &Bar<I, O>) -> bool {
| - help: consider adding an explicit lifetime bound `I: 'static`...
37 | Any::is::<u64>(b)
| ^
|
note: ...so that the type `Bar<I, O>` will meet its required lifetime bounds
--> src/main.rs:37:20
|
37 | Any::is::<u64>(b)
| ^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0310`.
error: Could not compile `playground`.
To learn more, run the command again with --verbose.