This question already has answers here:
Returning a closure from a function
(3 answers)
Closed last year.
I almost have an intuitive sense of why this code should NOT work, but I can't quite put my finger on it. I think it has something to do with the fact that the new function would have a different return type every time.
Why is that a problem? Why does the direct creation work?
struct Struct<T>
where
T: Fn(&[u8]),
{
func: T,
}
impl<T> Struct<T>
where
T: Fn(&[u8]),
{
fn new() -> Struct<T> {
// this doesn't work
Struct { func: |msg| {} }
}
}
fn main() {
// this works
let s = Struct { func: |msg| {} };
}
The error is
error[E0308]: mismatched types
--> src/main.rs:14:24
|
14 | Struct { func: |msg| {} }
| ^^^^^^^^ expected type parameter, found closure
|
= note: expected type `T`
found type `[closure@src/main.rs:14:24: 14:32]`
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
.