How can I store an async function in a struct and call it from a struct instance?

后端 未结 1 2046
闹比i
闹比i 2020-12-17 01:47

I\'m trying to achieve this with the new async/await syntax, std::future::Futures and a recent version of Tokio. I\'m using Tokio

相关标签:
1条回答
  • 2020-12-17 02:07

    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:

    • How do I call a function through a member variable?
    • How do I store a closure in a struct in Rust?
    0 讨论(0)
提交回复
热议问题