无法使用"Impl Future"将异步函数存储在向量中 [英] Cannot use `impl Future` to store async function in a vector

查看:202
本文介绍了无法使用"Impl Future"将异步函数存储在向量中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将async函数存储在向量中,但似乎impl不能在向量类型定义中使用:

I am trying to store async functions in a vector, but it seems like impl cannot be used in the vector type definition:

use std::future::Future;

fn main() {
    let mut v: Vec<fn() -> impl Future<Output = ()>> = vec![];

    v.push(haha);
}

async fn haha() {
    println!("haha");
}

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
 --> src/main.rs:4:28
  |
4 |     let mut v: Vec<fn() -> impl Future<Output = ()>> = vec![];
  |                            ^^^^^^^^^^^^^^^^^^^^^^^^

如何在向量中写入类型?

How do I write the type inside the vector?

我发现使用类型别名可能有解决方法,因此我更改了代码:

I found that there may be a workaround by using a type alias, so I changed the code:

use std::future::Future;

type Haha = impl Future<Output = ()>;

fn main() {
    let mut v: Vec<fn() -> Haha> = vec![];

    v.push(haha);
}

async fn haha() {
    println!("haha");
}

这也不起作用;这次错误发生在类型别名中:

This doesn't work either; this time the error occurs in the type alias:

error[E0658]: `impl Trait` in type aliases is unstable
 --> src/main.rs:3:1
  |
3 | type Haha = impl Future<Output = ()>;
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: for more information, see https://github.com/rust-lang/rust/issues/63063

error[E0308]: mismatched types
 --> src/main.rs:8:12
  |
8 |     v.push(haha);
  |            ^^^^ expected opaque type, found a different opaque type
  |
  = note: expected type `fn() -> Haha`
             found type `fn() -> impl std::future::Future {haha}`
  = note: distinct uses of `impl Trait` result in different opaque types

error: could not find defining uses
 --> src/main.rs:3:1
  |
3 | type Haha = impl Future<Output = ()>;
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我该如何解决?

推荐答案

您不能以这种方式使用impl Trait.为了能够将实现特征的不同类型存储到同一容器中,您必须使用动态分派,方法是存储类似Box<dyn Trait>的内容.

You cannot use the impl Trait this way. To be able to store different types that implement a trait into the same container you have to use dynamic dispatch, by storing something like Box<dyn Trait>.

在您的特定情况下,您不指定是要存储异步函数本身还是要存储由异步函数生成的将来,解决方案会有所不同.

In your particular case, you do not specify if you want to store the async functions themselves or the future generated by the async functions, the solution would be somewhat different.

要仅存储期货,请编写一个容器,例如:

To store just the futures, you write a container such as:

let mut v: Vec<Box<dyn Future<Output = ()>>> = vec![];

然后调用该函数,将其包装并存储在容器中:

And then just call the function, box it and store it in the container:

v.push(Box::new(haha()));

如果相反,您想存储异步函数本身而不调用它,则需要一个带双dyn的容器:

If instead you want to store the async function itself, without calling it, you need a container with a double dyn:

let mut v2: Vec<Box<dyn Fn() -> Box<dyn Future<Output = ()>>>> = vec![];

现在,由于您的haha函数未实现此Fn特征,因此您需要一个适配器. lambda函数可以,但是不要忘记双Box:

Now, since your haha function does not implement this Fn trait you need an adaptor. A lambda function will do, but don't forget the double Box:

v2.push(Box::new(|| Box::new(haha())));

不幸的是,使用这些解决方案,您将能够创建载体,但对于期货而言,则不能创建.await.为此,您需要期货来实现Unpin标记.这就向编译器保证了未来不会在运行时移动(如果这样做的话,实现将是完全不安全的).您可以在期货中添加+ Unpin要求,但async fn不是Unpin,因此您无法填充向量.修复此问题最简单的方法是使用std中的便捷功能:

Unfortunately, with these solutions you will be able to create the vector, but not to .await for your futures. For that you need the futures to implement the Unpin marker. That guarantees to the compiler that the future will not move while it is running (if it did, the implementation would be totally unsafe). You could add the + Unpin requirement to the futures, but async fn are not Unpin so you could not fill the vector. The easiest way to fix it is to use this handy function from std:

pub fn into_pin(boxed: Box<T>) -> Pin<Box<T>>

for f in v2 {
    f().into_pin().await;
}

不幸的是,它仍然不稳定.幸运的是,有一个From impl的功能完全相同.所以你可以这样写:

Unfortunately, it is still unstable. Fortunately, there is a From impl that does exactly the same. So you can just write:

for f in v2 {
    Pin::from(f()).await;
}

在下面的评论中,您编写此代码以等待期货:

In your comment below you write this code to wait for the futures:

for f in v2 {
    async { f().await }
}

请注意,async块本身将评估另一个未来,因此在这里,您只是将每个未来包装到另一个未来中,但是没有人在等待那个未来.实际上,您会收到关于它的警告:

Note that an async block itself will evaluate to another future, so here you are just wrapping each future into another future, but nobody is waiting for that one. Actually you'll get a warning about it:

警告:必须使用的未使用的std::future::Future实现程序.

请记住,为了正确等待所有期货,您将需要异步运行时.

Remember that in order to properly wait for all the futures you will need an async runtime.

这篇关于无法使用"Impl Future"将异步函数存储在向量中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆