如何避免添加'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), }) } }
关键修改说明
- 在
Exchangertrait的方法返回值、WebSocketExchanger的字段类型中,为trait 对象添加+ '_约束——这表示该 trait 对象的生命周期与当前上下文(即M的生命周期)绑定,而非强制要求'static。 - 无需修改
sink.with的闭包逻辑,因为闭包本身没有捕获外部变量,只是通过生命周期约束放宽了对M的要求。
内容的提问来源于stack exchange,提问作者leoha
相关产品推荐
相关产品推荐

