从 Rust 中的异步闭包调用存储的闭包
Call stored closure from an async closure in rust
我有一个闭包可以改变在它之外设计的变量。我将如何调用这个从异步范围内修改状态的闭包?
我有以下代码(抽象的,以显示问题):
#[tokio::main]
async fn main() {
let mut y = false;
let mut incr = |z: bool| {
y = z;
};
stream::iter(0..1).for_each(|_| async {
incr(true);
}).await;
});
产生以下内容:
error: captured variable cannot escape `FnMut` closure body
--> src/main.rs:40:37
|
36 | let mut incr = |z: bool| {
| -------- variable defined here
...
40 | stream::iter(0..1).for_each(|_| async {
| ___________________________________-_^
| | |
| | inferred to be a `FnMut` closure
41 | | incr(true);
| | ---- variable captured here
42 | | }).await;
| |_____^ returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
现在,我相信我明白了为什么会出现错误。我只是想不出解决这个问题的办法。
对于上下文:
- 我有一个 websocket 客户端,我正在从流中读取
- 每次我从流中接收数据时,我都在转换它
- 然后我需要用转换后的数据调用一个闭包以在其他地方使用——本质上就像 JavaScript 中的 EventEmitter。
我是不是走错了路?我是一名 JavaScript 开发人员,所以我必须在这里改变我的思维方式。
在rust中,通常需要使用某种同步机制。发送对普通变量的引用真的很困难。因此,您需要根据需要使用一些 Arc
、RwLock
、Mutex
。此外,您可能希望 move
将它们放入闭包中以避免生命周期问题。
在这种情况下,我认为 Arc<Cell>
可以:
use std::cell::Cell;
use std::sync::Arc;
use futures::StreamExt;
use futures::stream;
#[tokio::main]
async fn main() {
let yy = Arc::new(Cell::new(false));
let y = yy.clone();
let incr = move |z: bool| {
y.set(z);
};
stream::iter(0..1).for_each(|_| async {
incr(true);
}).await;
println!("{yy:?}");
}
查看 sync
进一步阅读。
以及 cell
documentation
我有一个闭包可以改变在它之外设计的变量。我将如何调用这个从异步范围内修改状态的闭包?
我有以下代码(抽象的,以显示问题):
#[tokio::main]
async fn main() {
let mut y = false;
let mut incr = |z: bool| {
y = z;
};
stream::iter(0..1).for_each(|_| async {
incr(true);
}).await;
});
产生以下内容:
error: captured variable cannot escape `FnMut` closure body
--> src/main.rs:40:37
|
36 | let mut incr = |z: bool| {
| -------- variable defined here
...
40 | stream::iter(0..1).for_each(|_| async {
| ___________________________________-_^
| | |
| | inferred to be a `FnMut` closure
41 | | incr(true);
| | ---- variable captured here
42 | | }).await;
| |_____^ returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
现在,我相信我明白了为什么会出现错误。我只是想不出解决这个问题的办法。
对于上下文:
- 我有一个 websocket 客户端,我正在从流中读取
- 每次我从流中接收数据时,我都在转换它
- 然后我需要用转换后的数据调用一个闭包以在其他地方使用——本质上就像 JavaScript 中的 EventEmitter。
我是不是走错了路?我是一名 JavaScript 开发人员,所以我必须在这里改变我的思维方式。
在rust中,通常需要使用某种同步机制。发送对普通变量的引用真的很困难。因此,您需要根据需要使用一些 Arc
、RwLock
、Mutex
。此外,您可能希望 move
将它们放入闭包中以避免生命周期问题。
在这种情况下,我认为 Arc<Cell>
可以:
use std::cell::Cell;
use std::sync::Arc;
use futures::StreamExt;
use futures::stream;
#[tokio::main]
async fn main() {
let yy = Arc::new(Cell::new(false));
let y = yy.clone();
let incr = move |z: bool| {
y.set(z);
};
stream::iter(0..1).for_each(|_| async {
incr(true);
}).await;
println!("{yy:?}");
}
查看 sync
进一步阅读。
以及 cell
documentation