You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust的retain回调中使用.await?

解决方案

核心问题分析

retain方法的闭包是同步执行的,无法容纳异步的.await调用(有界MPSC通道的send()需要异步等待),因此必须手动实现异步过滤逻辑,同时完成空Vec和HashMap键的清理。

修改后的代码

use tokio::sync::Mutex; // 确保使用tokio的异步Mutex
// ... 其他依赖

pub async fn broadcast(&self, message: Message) {
    let clients = self.clients.clone();
    let message = Arc::new(message);
    tokio::spawn(async move {
        // 异步获取锁,避免阻塞线程
        let mut clients = clients.lock().await;
        // 确保目标团队存在,不存在则直接返回
        let Some(players) = clients.get_mut(&message.team_id) else {
            return;
        };

        // 将HashMap条目取出,避免迭代时修改导致的借用冲突
        let player_entries: Vec<_> = players.drain().collect();
        
        for (player_id, mut emitters) in player_entries {
            let mut valid_emitters = Vec::new();
            // 异步发送消息,保留发送成功的发射器
            for emitter in emitters {
                if emitter.sender.send(message.clone()).await.is_ok() {
                    valid_emitters.push(emitter);
                }
            }
            
            // 仅当玩家还有有效发射器时,放回HashMap
            if !valid_emitters.is_empty() {
                players.insert(player_id, valid_emitters);
            }
        }

        // 若团队下无任何玩家,清理对应的团队ID条目
        if players.is_empty() {
            clients.remove(&message.team_id);
        }
    });
}

关键改动说明

  • 替换同步锁:将原代码中的std::sync::Mutex替换为tokio::sync::Mutex,使用.lock().await获取锁,避免在异步等待期间阻塞线程(标准库Mutex无法安全跨.await持有)。
  • 替代retain逻辑:通过drain()将HashMap条目全部转为Vec,遍历处理后仅保留有效条目,规避retain不支持异步闭包的限制。
  • 异步过滤:对每个发射器执行异步send(),仅保留发送成功的实例,确保无效连接被清理。
  • 层级清理:先清理玩家下的空发射器列表,再清理团队下的空玩家HashMap,完成两层空条目移除。

内容的提问来源于stack exchange,提问作者Fred Hors

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 12:07:50