Rust 未来生成器关闭时出错:捕获的变量无法转义`FnMut`关闭体
我想创建一个简单的websocket服务器。我想处理传入的消息并发送响应,但出现错误:Rust 未来生成器关闭时出错:捕获的变量无法转义`FnMut`关闭体,rust,async-await,Rust,Async Await,我想创建一个简单的websocket服务器。我想处理传入的消息并发送响应,但出现错误: 错误:捕获的变量无法转义`FnMut`闭包体 -->src\main.rs:32:27 | 32 |传入。对于每个| u(| m |异步{ | _________________________-_^ | | | ||推断为'FnMut'闭包 33 | |匹配m{ 34 | |//此处出错。。。 35 | | Ok(message)=>做点什么(message
错误:捕获的变量无法转义`FnMut`闭包体
-->src\main.rs:32:27
|
32 |传入。对于每个| u(| m |异步{
| _________________________-_^
| | |
||推断为'FnMut'闭包
33 | |匹配m{
34 | |//此处出错。。。
35 | | Ok(message)=>做点什么(message、db和mut传出)。等待,
36 | | Err(e)=>恐慌!(e)
37 | | }
等待;
|| ^返回对捕获的变量的引用,该变量将从闭包正文中转义
|
=注意:`FnMut`闭包在执行时只能访问其捕获的变量。。。
=注意:…因此,它们不能允许对捕获变量的引用转义
这会对堆栈溢出产生一些影响,但我在代码中没有看到任何变量正在转义的地方。异步块不会并发运行,所以我看不出有任何问题。此外,我觉得我正在做一件非常简单的事情:我得到了一个类型,它允许我将数据发送回客户端,但是当在异步块中使用对它的引用时,它会给出一个编译错误。只有在异步代码中使用outgoing
或db
变量时,才会发生错误
这是我的代码(错误出现在handle\u连接
功能中):
main.rs
use tokio::net::{TcpListener, TcpStream};
use std::net::SocketAddr;
use std::sync::Arc;
use futures::{StreamExt, SinkExt};
use tungstenite::Message;
use tokio_tungstenite::WebSocketStream;
struct DatabaseConnection;
#[tokio::main]
async fn main() -> Result<(), ()> {
listen("127.0.0.1:3012", Arc::new(DatabaseConnection)).await
}
async fn listen(address: &str, db: Arc<DatabaseConnection>) -> Result<(), ()> {
let try_socket = TcpListener::bind(address).await;
let mut listener = try_socket.expect("Failed to bind on address");
while let Ok((stream, addr)) = listener.accept().await {
tokio::spawn(handle_connection(stream, addr, db.clone()));
}
Ok(())
}
async fn handle_connection(raw_stream: TcpStream, addr: SocketAddr, db: Arc<DatabaseConnection>) {
let db = &*db;
let ws_stream = tokio_tungstenite::accept_async(raw_stream).await.unwrap();
let (mut outgoing, incoming) = ws_stream.split();
// Adding 'move' does also not work
incoming.for_each(|m| async {
match m {
// Error here...
Ok(message) => do_something(message, db, &mut outgoing).await,
Err(e) => panic!(e)
}
}).await;
}
async fn do_something(message: Message, db: &DatabaseConnection, outgoing: &mut futures_util::stream::SplitSink<WebSocketStream<TcpStream>, Message>) {
// Do something...
// Send some message
let _ = outgoing.send(Message::Text("yay".to_string())).await;
}
使用async move
时,出现以下错误:
代码
incoming.for_each(|m| async move {
let x = &mut outgoing;
let b = db;
}).await;
错误
error[E0507]:无法移出'FnMut'闭包中捕获的变量'outgoing'
-->src\main.rs:33:38
|
31 | let(mut传出,传入)=ws|u stream.split();
|------捕获的外部变量
32 |
33 |传入。对于每个| m |异步移动{
| ______________________________________^
34 | |设x=&mut;
| | --------
| | |
||发生移动是因为“outgoing”的类型为“futures”\u util::stream::stream::split::SplitSink`,它没有实现“Copy”特性
||因在发电机中使用而发生移动
35 | |设b=db;
等待;
|| uuuuu^移出“传出”发生在此处
FnMut
是一个匿名结构,由于FnMut
捕获了&mut传出的,因此它成为此匿名结构内部的一个字段,此字段将在每次调用FnMut
时使用,可以多次调用。如果您以某种方式丢失了它(通过返回或移动到另一个作用域等…),您的程序将无法使用该字段进行进一步调用,因为安全锈菌编译器不允许您这样做(对于这两种情况)
在您的情况下,我们可以使用它作为每个调用的参数,而不是捕获&mut outgoing
,这样我们将保留outgoing
的所有权。您可以使用from rs来完成此操作:
传入
.fold(传出,| mut传出,m |异步移动{
匹配m{
//这里有错误。。。
Ok(message)=>做点什么(message、db和mut传出)。等待,
错误(e)=>恐慌!(e),
}
外向的
})
.等待;
这似乎有点棘手,但它确实起到了作用,我们使用常量累加器(outgoing
),它将用作我们的FnMut
的参数
(感谢@Solomon Ucko创建可复制的示例)
另请参见:
错误消息抱怨的是哪个变量?@solomunucko这一行给了我一个错误,我不知道这个变量,因为错误消息没有说:Ok(message)=>dou_something(message,db,&mut outing)。等待,
可能尝试关闭move
(…move | m | async…
)从@SolomonUcko的链接,你可以使用fold
代替for\u each
来保持输出,这将修复编译错误,但我不知道是否有任何逻辑错误。我已经在我在上面的评论中分享的链接中解释了这个问题。@NoKey为什么这样使用请检查这个链接中的折叠解决方案:(我以前分享过)
incoming.for_each(|m| async move {
let x = &mut outgoing;
let b = db;
}).await;