Ken*_*eth 4 types asynchronous rust
我试图将async函数存储在向量中,但似乎impl不能在向量类型定义中使用:
use std::future::Future;
fn main() {
let mut v: Vec<fn() -> impl Future<Output = ()>> = vec![];
v.push(haha);
}
async fn haha() {
println!("haha");
}
Run Code Online (Sandbox Code Playgroud)
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![];
| ^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
如何在向量中写入类型?
我发现使用类型别名可能有一个解决方法,所以我更改了代码:
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");
}
Run Code Online (Sandbox Code Playgroud)
这也不起作用;这次错误发生在类型别名中:
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 = ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
我如何解决它?
你不能使用impl Trait这种方式。为了能够将实现 trait 的不同类型存储到同一个容器中,您必须使用动态调度,通过存储类似Box<dyn Trait>.
在您的特定情况下,您没有指定是要存储异步函数本身还是由异步函数生成的未来,解决方案会有所不同。
要仅存储期货,您可以编写一个容器,例如:
let mut v: Vec<Box<dyn Future<Output = ()>>> = vec![];
Run Code Online (Sandbox Code Playgroud)
然后只需调用该函数,将其装箱并将其存储在容器中:
v.push(Box::new(haha()));
Run Code Online (Sandbox Code Playgroud)
相反,如果您想存储异步函数本身而不调用它,则需要一个带有 double 的容器dyn:
let mut v2: Vec<Box<dyn Fn() -> Box<dyn Future<Output = ()>>>> = vec![];
Run Code Online (Sandbox Code Playgroud)
现在,由于你的haha函数没有实现这个Fn特性,你需要一个适配器。一个 lambda 函数可以,但不要忘记 double Box:
v2.push(Box::new(|| Box::new(haha())));
Run Code Online (Sandbox Code Playgroud)
不幸的是,使用这些解决方案,您将能够创建向量,但不能.await用于您的未来。为此,您需要期货来实现Unpin标记。这向编译器保证未来在它运行时不会移动(如果它移动了,实现将是完全不安全的)。您可以将+ Unpin要求添加到期货中,但async fn不是Unpin这样您就无法填充向量。修复它的最简单方法是使用以下方便的功能std:
pub fn into_pin(boxed: Box<T>) -> Pin<Box<T>>
for f in v2 {
f().into_pin().await;
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,它仍然不稳定。幸运的是,有一个From实现完全相同的实现。所以你可以写:
for f in v2 {
Pin::from(f()).await;
}
Run Code Online (Sandbox Code Playgroud)
在下面的评论中,您编写此代码以等待期货:
for f in v2 {
async { f().await }
}
Run Code Online (Sandbox Code Playgroud)
请注意,一个async块本身将评估另一个未来,所以在这里你只是将每个未来包装到另一个未来,但没有人在等待那个未来。实际上,您会收到有关它的警告:
警告:
std::future::Future必须使用未使用的实现者。
请记住,为了正确等待所有期货,您将需要一个异步运行时。
rodrigo 的答案是正确的,但我更喜欢使用Box::pin该类型并将其烘焙Pin到集合的 API 中。这使得使用Future特征对象(或生成特征对象的闭包特征Future对象)变得更容易:
use std::{future::Future, pin::Pin};
type PinFutureObj<Output> = Pin<Box<dyn Future<Output = Output>>>;
async fn collection_of_pinned_future_trait_objects() {
let v: Vec<PinFutureObj<()>> = vec![
Box::pin(haha()),
Box::pin(hehe()),
Box::pin(haha()),
Box::pin(hehe()),
];
for f in v {
f.await
}
}
async fn collection_of_closure_trait_objects() {
let v: Vec<Box<dyn Fn() -> PinFutureObj<()>>> = vec![
Box::new(|| Box::pin(haha())),
Box::new(|| Box::pin(hehe())),
Box::new(|| Box::pin(haha())),
Box::new(|| Box::pin(hehe())),
];
for f in v {
f().await
}
}
async fn haha() {
println!("haha");
}
async fn hehe() {
println!("hehe");
}
Run Code Online (Sandbox Code Playgroud)
我还将开始为较长的类型引入类型别名。
事实上,这个类型别名已经存在于 futures 箱中,并且LocalBoxFuture可以通过FutureExt::boxed_local. 还产生了添加共同特征界限BoxFuture的产品。FutureExt::boxed
use futures::future::{FutureExt, LocalBoxFuture}; // 0.3.5
async fn collection_of_pinned_future_trait_objects() {
let v: Vec<LocalBoxFuture<'static, ()>> = vec![
haha().boxed_local(),
hehe().boxed_local(),
haha().boxed_local(),
hehe().boxed_local(),
];
for f in v {
f.await
}
}
async fn collection_of_closure_trait_objects() {
let v: Vec<Box<dyn Fn() -> LocalBoxFuture<'static, ()>>> = vec![
Box::new(|| haha().boxed_local()),
Box::new(|| hehe().boxed_local()),
Box::new(|| haha().boxed_local()),
Box::new(|| hehe().boxed_local()),
];
for f in v {
f().await
}
}
async fn haha() {
println!("haha");
}
async fn hehe() {
println!("hehe");
}
Run Code Online (Sandbox Code Playgroud)
也可以看看:
| 归档时间: |
|
| 查看次数: |
3122 次 |
| 最近记录: |