Let's use this as our Minimal, Reproducible Example:
async fn foo(x: u8) -> u8 {
2 * x
}
struct S {
foo: (),
}
async fn example() {
let s = S { foo };
}
It produces the error:
error[E0308]: mismatched types
--> src/main.rs:10:17
|
10 | let s = S { foo };
| ^^^ expected (), found fn item
|
= note: expected type `()`
found type `fn(u8) -> impl std::future::Future {foo}`
The type of foo
is a function pointer that takes a u8
and returns some type implementing the trait std::future::Future
. async fn
is effectively just syntax sugar that transforms -> Foo
into -> impl Future<Output = Foo>
.
We make our struct generic and place a trait bound on the generic that matches. In real code, you'd probably want to place a constraint on the the Output
associated type, but it's not needed for this example. We can then call the function like any other callable member field:
async fn foo(x: u8) -> u8 {
2 * x
}
struct S<F>
where
F: std::future::Future,
{
foo: fn(u8) -> F,
}
impl<F> S<F>
where
F: std::future::Future,
{
async fn do_thing(self) {
(self.foo)(42).await;
}
}
async fn example() {
let s = S { foo };
s.do_thing().await;
}
To be even more flexible, you could use another generic to store a closure, instead of forcing only a function pointer:
struct S<C, F>
where
C: Fn(u8) -> F,
F: std::future::Future,
{
foo: C,
}
impl<C, F> S<C, F>
where
C: Fn(u8) -> F,
F: std::future::Future,
{
async fn do_thing(self) {
(self.foo)(42).await;
}
}
See also:
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…