tl;dr; You can do the following:
fn new() -> Struct<impl Fn(&[u8])> {
Struct { func: |msg| {} }
}
More detailed:
Let's dissect your impl
block:
impl<T> Struct<T>
where
T: Fn(&[u8]),
{
fn new() -> Struct<T> {
// this doesn't work
Struct { func: |msg| {} }
}
}
We start with:
impl<T> Struct<T>
where
T: Fn(&[u8]),
This tells the compiler that the whole impl
block is "valid" for any T
satisfying Fn(&[u8])
.
Now:
fn new() -> Struct<T> {
// this doesn't work
Struct { func: |msg| {} }
}
You say that new
returns a Struct<T>
, and we are within the block stating that everything inside it works for any T
satisfying Fn(&[u8])
. However, you return one particular instance of Struct
, namely the one parametrized by |msg| {}
- thus, the return value can not be a Struct<T>
for any T
satisfying Fn(&[u8])
.
However, you can modify it to do the following:
fn new() -> Struct<impl Fn(&[u8])> {
Struct { func: |msg| {} }
}
This tells the compiler that new
returns a Struct
, whose parameter is known to satisfy Fn(&[u8])
, so that the compiler should infer it. In particular it has no assumptions about T
and returns one particular type.
In the direct initialization, however, we tell the compiler:
let s = Struct { func: |msg| {} };
The compiler sees that you want to create a Struct
and knows that - in order to create it - it must infer the type for T
res. func
. It sees that you passed |msg| {}
for func
, infers the type for the closure and now knows a concrete type to put into the T
.