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

如何封装等待tokio::sync::watch::Receiver变为Some的异步函数?

解决Tokio Watch Receiver异步等待Some值的借用检查错误

修正后的完整代码

use std::ops::Deref;

use tokio::sync::watch;

pub struct WatchSomeRef<'a, T>(watch::Ref<'a, Option<T>>);

impl<T> Deref for WatchSomeRef<'_, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        self.0.as_ref().unwrap()
    }
}

pub async fn recv_some<'a, T>(
    rx: &'a mut watch::Receiver<Option<T>>,
) -> Result<WatchSomeRef<'a, T>, watch::error::RecvError> {
    loop {
        let guard = {
            // 获取最新值的引用
            let current_guard = rx.borrow_and_update();
            if current_guard.is_some() {
                current_guard
            } else {
                // 显式释放对rx的可变借用
                drop(current_guard);
                // 等待值发生变更
                rx.changed().await?;
                // 回到循环开头重新检查
                continue;
            }
        };
        return Ok(WatchSomeRef(guard));
    }
}

问题根源

你的代码核心矛盾在于编译器无法自动推断循环中guard的生命周期边界:

  • 当guard持有Some(T)时,它需要和输入的rx保持相同生命周期(因为返回值依赖这个借用);
  • 当guard持有None时,它需要立即销毁以释放rx的可变借用,让后续的rx.changed()能再次借用rx。

原循环结构中,编译器看到return分支会让guard绑定到rx的整个生命周期,同时又检测到循环后续需要再次可变借用rx,因此抛出冲突错误。

解决思路

通过显式拆分逻辑分支,让编译器明确两种场景的边界:

  1. 在独立代码块中获取current_guard并检查值:
    • 若为Some,直接将current_guard传递到外层作为返回值的一部分;
    • 若为None,显式调用drop(current_guard)释放借用,等待变更后重新进入循环。
  2. 给函数签名添加显式生命周期标注'a,明确返回的WatchSomeRef生命周期与输入rx绑定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 06:57:22