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

如何避免添加'static约束,编译含async闭包的Rust WebSocket代码?

解决Rust WebSocketExchanger无需'static约束的问题

编译器要求添加'static约束的核心原因是:默认情况下,Pin<Box<dyn Sink<...>>>这类 trait 对象会被推断为拥有'static生命周期,这就强制要求泛型参数M必须满足'static。问题出在sink.with生成的闭包被装箱时,默认的 trait 对象生命周期约束过严。

解决方案

通过显式为 trait 对象指定匿名生命周期('_),让其生命周期与M的生命周期绑定,避免强制'static约束。只需调整Exchanger trait、WebSocketExchanger的字段类型即可,无需修改核心逻辑。

修改后的完整代码

use futures_util::{Sink, SinkExt, Stream, StreamExt};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::pin::Pin;
use tokio_tungstenite::connect_async;
use tokio_tungstenite::tungstenite::client::IntoClientRequest;
use tokio_tungstenite::tungstenite::Message;

pub trait Exchanger<M: Serialize + DeserializeOwned> {
    fn receiver(&mut self) -> &mut Pin<Box<dyn Stream<Item = anyhow::Result<M>> + '_>>;
    fn sender(&mut self) -> &mut Pin<Box<dyn Sink<M, Error = anyhow::Error> + '_>>;
}

pub struct WebSocketExchanger<M: Serialize + DeserializeOwned> {
    stream: Pin<Box<dyn Stream<Item = anyhow::Result<M>> + '_>>,
    sink: Pin<Box<dyn Sink<M, Error = anyhow::Error> + '_>>,
}

impl<M: Serialize + DeserializeOwned> Exchanger<M> for WebSocketExchanger<M> {
    fn receiver(&mut self) -> &mut Pin<Box<dyn Stream<Item = anyhow::Result<M>> + '_>> {
        &mut self.stream
    }

    fn sender(&mut self) -> &mut Pin<Box<dyn Sink<M, Error = anyhow::Error> + '_>> {
        &mut self.sink
    }
}

impl<M: Serialize + DeserializeOwned> WebSocketExchanger<M> {
    pub async fn connect<R: IntoClientRequest + Unpin>(request: R) -> anyhow::Result<Self> {
        let (web_socket, _) = connect_async(request).await?;
        let (web_socket_sink, web_socket_stream) = web_socket.split();

        let sink = web_socket_sink.with(|x: M| async move {
            serde_json::to_string(&x)
                .map_err(anyhow::Error::from)
                .map(|s| Message::text(s))
        });

        let stream = web_socket_stream
            .map(|m| match m {
                Ok(message) => anyhow::Ok(message),
                Err(err) => Err(anyhow::Error::from(err)),
            })
            .map(|m| match m {
                Ok(msg) => anyhow::Ok(serde_json::from_str::<M>(msg.to_text()?)?),
                Err(err) => Err(err),
            });

        anyhow::Ok(Self {
            stream: Box::pin(stream),
            sink: Box::pin(sink),
        })
    }
}

关键修改说明

  1. 在Exchanger trait的方法返回值、WebSocketExchanger的字段类型中,为trait 对象添加+ '_约束——这表示该 trait 对象的生命周期与当前上下文(即M的生命周期)绑定,而非强制要求'static。
  2. 无需修改sink.with的闭包逻辑,因为闭包本身没有捕获外部变量,只是通过生命周期约束放宽了对M的要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 19:05:23