我正试图用新的async/await语法、std::future::Futures和Tokio的最新版本来实现这一点.我用的是Tokio 0.2.0-alpha.4和Rust 1.39.0-nightly.

我try 过的不同事情包括:

  • 对我要存储在 struct 中的类型使用Box<dyn>
  • 在 struct 定义中使用泛型

我无法得到一个最低限度的工作版本,所以这里是我试图实现的一个简化版本:

async fn foo(x: u8) -> u8 {
    2 * x
}

// type StorableAsyncFn = Fn(u8) -> dyn Future<Output = u8>;

struct S {
    f: StorableAsyncFn,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let s = S { f: foo };

    let out = (s.f)(1).await;

    Ok(())
}

当然,这段代码无法编译,出现以下错误:

error[E0412]: cannot find type `StorableAsyncFn` in this scope

这里没有定义StorableAsyncFn,这是我试图定义的类型.

推荐答案

让我们用这个作为我们的Minimal, Reproducible Example:

async fn foo(x: u8) -> u8 {
    2 * x
}

struct S {
    foo: (),
}

async fn example() {
    let s = S { foo };
}

它会产生以下错误:

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}`

foo的类型是一个函数指针,它接受u8并返回实现trait std::future::Future的某种类型.async fn实际上只是将-> Foo转换成-> impl Future<Output = Foo>的语法糖.

我们将 struct 设为泛型,并将特征绑定到匹配的泛型上.在实际代码中,您可能希望在Output个关联类型上放置一个约束,但在本例中不需要.然后,我们可以像调用任何其他可调用成员字段一样调用该函数:

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;
}

为了更加灵活,您可以使用另一个泛型来存储闭包,而不是只强制使用函数指针:

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;
    }
}

另见:

Rust相关问答推荐

as操作符如何将enum转换为int?

如何从polars DataFrame中获取一个列作为Option String?<>

trait声明中的生命周期参数

如果成员都实现特征,是否在多态集合上实现部分重叠的特征?

通过使用光标拖动角来绕其中心旋转矩形

带参考文献的 rust 元组解构

在铁 rust 中,如何一次只引用几件事中的一件?

是否提供Bundle 在可执行文件中的warp中的静态文件?

为什么rustc会自动降级其版本?

Rust从关联函数启动线程

为什么RefCell没有与常规引用相同的作用域?

如何限制 GtkColumnView 行数

如何获取模块树?

如何在 Rust 中显式声明 std::str::Matches<'a, P> ?

有什么方法可以通过使用生命周期来减轻嵌套生成器中的当生成器产生时borrow 可能仍在使用错误?

如何判断服务器是否正确接收数据

`移动||异步移动{...}`,如何知道哪个移动正在移动哪个?

如何将 Rust 字符串转换为 i8(c_char) 数组?

在异步 Rust 中,Future 如何确保它只调用最近的 Waker?

使用方法、关联函数和自由函数在 Rust 中初始化函数指针之间的区别