Sim*_* S. 4 asynchronous future rust async-await
我想要await
一个async
在迭代器中使用的闭包内的函数。需要闭包的函数在结构体实现中被调用。我无法弄清楚如何做到这一点。
这段代码模拟了我正在尝试做的事情:
struct MyType {}
impl MyType {
async fn foo(&self) {
println!("foo");
(0..2).for_each(|v| {
self.bar(v).await;
});
}
async fn bar(&self, v: usize) {
println!("bar: {}", v);
}
}
#[tokio::main]
async fn main() {
let mt = MyType {};
mt.foo().await;
}
Run Code Online (Sandbox Code Playgroud)
显然,这将不起作用,因为闭包不是async
,给我:
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> src/main.rs:8:13
|
7 | (0..2).for_each(|v| {
| --- this is not `async`
8 | self.bar(v).await;
| ^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
Run Code Online (Sandbox Code Playgroud)
在寻找有关如何async
从非函数调用函数的答案后async
,我想到了这个:
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> src/main.rs:8:13
|
7 | (0..2).for_each(|v| {
| --- this is not `async`
8 | self.bar(v).await;
| ^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
Run Code Online (Sandbox Code Playgroud)
但现在我正在解决终身问题:
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> src/main.rs:4:18
|
4 | async fn foo(&self) {
| ^^^^^
| |
| this data with an anonymous lifetime `'_`...
| ...is captured here...
...
8 | tokio::spawn(async move {
| ------------ ...and is required to live as long as `'static` here
Run Code Online (Sandbox Code Playgroud)
这也不令我感到惊讶,因为据我所知,Rust 编译器无法知道线程将存活多长时间。鉴于此,生成的线程tokio::spawn
可能比 type 的寿命更长MyType
。
我想出的第一个解决方法是创建bar
一个关联函数,复制我在闭包中需要的所有内容并将其作为值传递给bar
并调用它,MyType::bar(copies_from_self)
但这变得越来越难看,因为有很多复制。这也感觉像是一种不知道生命周期如何运作的解决方法。
相反,我试图将futures::executor::block_on
which 用于简单的任务,例如这篇文章中的任务:
tokio::spawn(async move {
self.bar(v).await;
});
Run Code Online (Sandbox Code Playgroud)
但是当把它放在我使用第三方库1 的现实生活示例中时,它也使用了tokio
,事情不再起作用。阅读文档后,我意识到这#[tokio::main]
是一个最终将所有内容包装起来的宏,block_on
因此通过这样做将嵌套block_on
. 这可能是async
调用的方法之一bar
停止工作而没有任何错误或日志记录的原因(没有任何错误或日志记录(block_on
因此不应该对代码产生任何影响)。我联系了那些说我可以使用的作者,for_each(|i| async move { ... })
这让我更加困惑。
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> src/main.rs:4:18
|
4 | async fn foo(&self) {
| ^^^^^
| |
| this data with an anonymous lifetime `'_`...
| ...is captured here...
...
8 | tokio::spawn(async move {
| ------------ ...and is required to live as long as `'static` here
Run Code Online (Sandbox Code Playgroud)
会导致编译错误
expected `()`, found opaque type`
Run Code Online (Sandbox Code Playgroud)
我认为这是有道理的,因为我现在要返回一个未来而不是()
. 我对此的天真方法是尝试用这样的方法等待未来:
(0..2).for_each(|v| {
futures::executor::block_on(self.bar(v));
});
Run Code Online (Sandbox Code Playgroud)
但这让我回到了第一个,导致了以下编译错误,我也认为这是有道理的,因为我现在又回到了await
在sync
.
only allowed inside `async` functions and blocks` since the
Run Code Online (Sandbox Code Playgroud)
毕竟这种货物崇拜编程的问题基本上是,是否有可能,如果有,我如何async
从迭代器中的闭包调用我的函数(最好不产生线程以避免生命周期问题)?如果这是不可能的,那么惯用的实现会是什么样的?
Iterator::for_each
期望同步 clsure,因此您不能.await
在其中使用(至少不能直接使用),也不能从中返回未来。
一种解决方案是只使用for
循环而不是.for_each
:
for v in 0..2 {
self.bar(v).await;
}
Run Code Online (Sandbox Code Playgroud)
更通用的方法是使用流而不是迭代器,因为它们是异步等效的(并且流上的等效方法通常也是异步的)。这不仅适用for_each
于大多数其他迭代器方法,而且适用于:
use futures::prelude::*;
futures::stream::iter(0..2)
.for_each(|c| async move {
self.bar(v).await;
})
.await;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1428 次 |
最近记录: |