I have a struct that contains a function object:
struct Foo<F> {
func: F,
}
I want to add an Fn
trait bound to the struct definition. The problem is: I do care about the first parameter (it has to be i32
), but not the second one. What I actually want to write is something like this:
struct Foo<F>
where
∃ P so that F: Fn(i32, P),
{
func: F,
}
So in English: the type F
has to be a function that takes two parameters, the first of which is an i32
(and the second one can be anything). The syntax above is obviously not valid. I thought about three potential solutions:
The
for<>
syntax won't help here. Apart from the fact that it doesn't work for non-lifetime parameter yet, it is universal ("for all") and not existential ("there exists"). So that's out.The other possibility is to add a type parameter to the struct. I already don't like that solution, because the parameter doesn't inherently belong to the struct.
struct Foo<F, P> where F: Fn(i32, P), { func: F, }
But this doesn't work: the parameter
P
is not used, except in thewhere
bound, so the compiler complains.This problem can be solved by adding a
PhantomData<P>
field, but this shouldn't be necessary and more importantly, users cannot use the struct constructor syntax easily anymore.Lastly I tried this:
struct Foo<F> where F: Fn(i32, _), { func: F, }
But this also doesn't work:
error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> src/main.rs:3:20 | 3 | F: Fn(i32, _), | ^ not allowed in type signatures
Is there a way to achieve what I want?
Side note: Why do I want to have the trait bound on the struct already instead of just the impl
blocks where it's important?
First, once the "implied trait bounds" RFC is implemented, this allows me to omit the duplicate trait bounds from all the impl
blocks. Second, with this bound, it helps the compiler with its type inference. Consider this:
struct Foo<F, T>
where
F: Fn(T, _),
{
data: T,
F: F,
}
If the bound were possible (I tried it with the PhantomData
"solution" above), the compiler can more easily infer the type of the closure's first argument. If the trait bounds would only be specified on impl blocks, the compiler has difficulties.