Rust 未来生成器关闭时出错:捕获的变量无法转义`FnMut`关闭体

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

我想创建一个简单的websocket服务器。我想处理传入的消息并发送响应,但出现错误:

错误:捕获的变量无法转义`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;