提问人:Lomírus 提问时间:2/8/2023 最后编辑:Lomírus 更新时间:2/9/2023 访问量:239
无法移出异步“Fn”闭包中捕获的变量
cannot move out of a captured variable in an async `Fn` closure
问:
这是我的代码。在这个程序中,我想创建一个简单的 websocket 服务器。当用户向 发送请求时,浏览器将与服务器建立 websocket 连接。ws://{url}/
use std::{collections::HashMap, sync::Arc};
use async_std::{prelude::*, sync::Mutex};
use tide_websockets::WebSocket;
use uuid::Uuid;
#[async_std::main]
async fn main() {
let connections = Arc::new(Mutex::new(HashMap::new()));
let mut app = tide::new();
app.at("/").get(WebSocket::new(move |_, mut stream| async move {
let uuid = Uuid::new_v4();
// Add the connection to clients when opening a new connection
connections.lock().await.insert(uuid, stream.clone());
// Waiting for the connection to be closed
while let Some(Ok(_)) = stream.next().await {}
// Remove the connection from clients when it is closed
connections.lock().await.remove(&uuid);
Ok(())
}));
// app.bind(url).await
}
当我尝试编译这个程序时,rustc 说:
error[E0507]: cannot move out of `connections`, a captured variable in an `Fn` closure
--> src/main.rs:11:57
|
9 | let connections = Arc::new(Mutex::new(HashMap::new()));
| ----------- captured outer variable
10 | let mut app = tide::new();
11 | app.at("/").get(WebSocket::new(move |_, mut stream| async move {
| ____________________________________--------------------_^
| | |
| | captured by this `Fn` closure
12 | | let uuid = Uuid::new_v4();
13 | |
14 | | // Add the connection to clients when opening a new connection
15 | | connections.lock().await.insert(uuid, stream.clone());
| | -----------
| | |
| | variable moved due to use in generator
| | move occurs because `connections` has type `Arc<async_std::sync::Mutex<HashMap<Uuid, WebSocketConnection>>>`, which does not implement the `Copy` trait
... |
23 | | Ok(())
24 | | }));
| |_____^ move out of `connections` occurs here
For more information about this error, try `rustc --explain E0507`.
error: could not compile `mre` due to previous error
这是该方法的定义(不确定它是否有用):Websocket::new
impl<S, H, Fut> WebSocket<S, H>
where
S: Send + Sync + Clone + 'static,
H: Fn(Request<S>, WebSocketConnection) -> Fut + Sync + Send + 'static,
Fut: Future<Output = Result<()>> + Send + 'static,
{
/// Build a new WebSocket with a handler function that
pub fn new(handler: H) -> Self {
Self {
handler: Arc::new(handler),
ghostly_apparition: PhantomData,
protocols: Default::default(),
}
}
// ...
}
在发布这个问题之前,我尝试搜索这个问题。大多数答案要么是无关紧要的,要么需要修改方法的源代码(这里是方法)。但是这个方法不是我写的,而是来自第三方的板条箱。还有什么方法可以解决这个问题吗?Websocket::new
答:
1赞
Finomnis
2/9/2023
#1
的参数必须是闭包,这意味着它必须是可重复调用的。WebSocket::new()
Fn
但是,在代码中,它在内部使用 a 中的变量,这意味着它将变量移动到块中。由于显而易见的原因,这只能执行一次。connections
async move
async
不过,这很容易修复。您需要创建变量的新引用,并将该引用移动到 .因此,每个调用都会获得自己的副本,使其与 .connections
Arc
connections
async move
Fn
下面是一个编译版本:
use std::{collections::HashMap, sync::Arc};
use async_std::{prelude::*, sync::Mutex};
use tide_websockets::WebSocket;
use uuid::Uuid;
#[async_std::main]
async fn main() {
let connections = Arc::new(Mutex::new(HashMap::new()));
let mut app = tide::new();
app.at("/").get(WebSocket::new(move |_, mut stream| {
let connections = Arc::clone(&connections);
async move {
let uuid = Uuid::new_v4();
// Add the connection to clients when opening a new connection
connections.lock().await.insert(uuid, stream.clone());
// Waiting for the connection to be closed
while let Some(Ok(_)) = stream.next().await {}
// Remove the connection from clients when it is closed
connections.lock().await.remove(&uuid);
Ok(())
}
}));
// app.bind(url).await
}
评论
70
stream
}));