As @VladimirMatveev says , the return type of the closure is an associated type.
The associated type is different from the type parameter, because its value is determined when the attribute is implemented, and not when it is used in a call.
In Fn(I) -> Option<T> , when you have an input (type I ) and an implementation (specific operations defined in the closure that you go through), the output of Option<T> defined.
For I this is different. You need to either use the type in the structure or show the compiler how it will be theoretically used with the PhantomData field.
use std::marker::PhantomData; struct Bar<I, T, F> where F: Fn(I) -> Option<T>, { f: F, _marker: PhantomData<I>, }
PhantomData used only for type checking, but it is erased in the generated code, so it does not occupy any memory in your structure (why is it a phantom).
The reason why this is necessary is explained in detail in the rejection of RFC 738 . I will try to give you a shorter (and hopefully correct) version here.
In Rust, you can in most cases (but not always!) Use a longer service life where a shorter one is expected.
fn foo<'short, 'long>(_a: &'short i32, b: &'long i32) where 'long: 'short, { let _shortened: &'short i32 = b; // we're binding b to a shorter lifetime } fn foo2<'short, 'long>(_a: &'short i32, b: &'long Cell<&'long i32>) where 'long: 'short, { let _shortened: &Cell<&'short i32> = b; }
( playground )
The RFC explains why Cell expects the exact same (and no longer) lifetime, but now I suggest you just trust the compiler, which would be unsafe to compile foo2 .
Now pretend you have
struct Foo<T> { t: T }
That T can be anything, including a type containing references.
In particular, T may be a type of type & i32 or a type of type &Cell<&i32> .
As with our foo functions above, Rust can only crash when it can or cannot allow us to assign a shorter lifespan by checking the type T ( playground ).
However, when you have a parameter for an unused type, the inference does not have a check box to know how it should allow the type to behave over time.
If you
struct Foo<T>;
Rust asks you to point with PhantomType if you want your T to behave as if it were & i32 or as Cell . You must write:
struct Foo<T> { marker: PhantomData<T>,
or you can write:
struct Foo<T> { marker: PhantomData<Cell<T>> }