从闭包中调用异步函数
Calling async function from closure
我想 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;
}
显然,这不会起作用,因为闭包不是 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
在寻找关于如何从非 async
函数调用 async
函数的答案后,我编辑了这个:
tokio::spawn(async move {
self.bar(v).await;
});
但现在我遇到了终身问题:
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
这也不让我感到惊讶,因为据我所知,Rust 编译器无法知道线程将存活多长时间。鉴于此,使用 tokio::spawn
生成的线程可能比 MyType
.
类型的寿命更长
我想出的第一个修复方法是使 bar
成为一个关联函数,将我需要的所有内容复制到我的闭包中并将其作为值传递给 bar
并使用 [=28 调用它=] 但是由于有很多复制,这变得很难看。它也感觉像是不知道生命周期如何工作的解决方法。
我改为尝试使用 futures::executor::block_on
,它适用于像 post:
中的简单任务
(0..2).for_each(|v| {
futures::executor::block_on(self.bar(v));
});
但是当我把它放在我使用第三方库1(也使用tokio
)的现实生活中时,事情就不再有效了。阅读文档后,我意识到 #[tokio::main]
是一个最终将所有内容包装在 block_on
中的宏,因此通过这样做将嵌套 block_on
。这可能是为什么在 bar
中调用的 async
方法之一只是停止工作而没有任何错误或日志记录的原因(没有 block_on
工作所以不应该与代码有任何关系)。我联系了那些说我可以使用 for_each(|i| async move { ... })
的作者,这让我更加困惑。
(0..2).for_each(|v| async move {
self.bar(v).await;
});
会导致编译错误
expected `()`, found opaque type`
我认为这是有道理的,因为我现在返回的是未来而不是 ()
。我天真的做法是尝试用这样的方式等待未来:
(0..2).for_each(|v| {
async move {
self.bar(v).await;
}
.await
});
但这让我回到原点,导致以下编译错误,我也认为这是有道理的,因为我现在回到在 sync
的闭包中使用 await
。
only allowed inside `async` functions and blocks` since the
这个发现也让我很难利用找到的答案,例如 here and 。
所有这些货物崇拜编程之后的问题基本上是,是否可能,如果可能,我如何从闭包 中调用我的 async
函数(最好没有在迭代器中生成线程以避免生命周期问题)?如果这不可能,那么它的惯用实现是什么样的?
Iterator::for_each
期望同步关闭,因此您不能在其中使用 .await
(至少不能直接使用),您也不能 return 从中获得未来。
一个解决方案是只使用 for
循环而不是 .for_each
:
for v in 0..2 {
self.bar(v).await;
}
更通用的方法是使用 streams 而不是迭代器,因为它们是异步等效的(并且流上的等效方法通常也是异步的)。这不仅适用于 for_each
,而且适用于大多数其他迭代器方法:
use futures::prelude::*;
futures::stream::iter(0..2)
.for_each(|c| async move {
self.bar(v).await;
})
.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;
}
显然,这不会起作用,因为闭包不是 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
在寻找关于如何从非 async
函数调用 async
函数的答案后,我编辑了这个:
tokio::spawn(async move {
self.bar(v).await;
});
但现在我遇到了终身问题:
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
这也不让我感到惊讶,因为据我所知,Rust 编译器无法知道线程将存活多长时间。鉴于此,使用 tokio::spawn
生成的线程可能比 MyType
.
我想出的第一个修复方法是使 bar
成为一个关联函数,将我需要的所有内容复制到我的闭包中并将其作为值传递给 bar
并使用 [=28 调用它=] 但是由于有很多复制,这变得很难看。它也感觉像是不知道生命周期如何工作的解决方法。
我改为尝试使用 futures::executor::block_on
,它适用于像 post:
(0..2).for_each(|v| {
futures::executor::block_on(self.bar(v));
});
但是当我把它放在我使用第三方库1(也使用tokio
)的现实生活中时,事情就不再有效了。阅读文档后,我意识到 #[tokio::main]
是一个最终将所有内容包装在 block_on
中的宏,因此通过这样做将嵌套 block_on
。这可能是为什么在 bar
中调用的 async
方法之一只是停止工作而没有任何错误或日志记录的原因(没有 block_on
工作所以不应该与代码有任何关系)。我联系了那些说我可以使用 for_each(|i| async move { ... })
的作者,这让我更加困惑。
(0..2).for_each(|v| async move {
self.bar(v).await;
});
会导致编译错误
expected `()`, found opaque type`
我认为这是有道理的,因为我现在返回的是未来而不是 ()
。我天真的做法是尝试用这样的方式等待未来:
(0..2).for_each(|v| {
async move {
self.bar(v).await;
}
.await
});
但这让我回到原点,导致以下编译错误,我也认为这是有道理的,因为我现在回到在 sync
的闭包中使用 await
。
only allowed inside `async` functions and blocks` since the
这个发现也让我很难利用找到的答案,例如 here and
所有这些货物崇拜编程之后的问题基本上是,是否可能,如果可能,我如何从闭包 中调用我的 async
函数(最好没有在迭代器中生成线程以避免生命周期问题)?如果这不可能,那么它的惯用实现是什么样的?
Iterator::for_each
期望同步关闭,因此您不能在其中使用 .await
(至少不能直接使用),您也不能 return 从中获得未来。
一个解决方案是只使用 for
循环而不是 .for_each
:
for v in 0..2 {
self.bar(v).await;
}
更通用的方法是使用 streams 而不是迭代器,因为它们是异步等效的(并且流上的等效方法通常也是异步的)。这不仅适用于 for_each
,而且适用于大多数其他迭代器方法:
use futures::prelude::*;
futures::stream::iter(0..2)
.for_each(|c| async move {
self.bar(v).await;
})
.await;