传递Bytes至函数引发生命周期错误的原因及修复方案
Rust Bytes生命周期错误分析与修复
问题场景
调用方代码(send_msg函数)
pub async fn send_msg(online_users: Arc<Mutex<OnlineUsers>>, msg: &Message, from: &str) -> io::Result<()> { let target_user = msg.args.get(0).ok_or(io::Error::from(io::ErrorKind::InvalidInput))?; if let Content::Text(ref text) = msg.content { let text_owned = text.clone(); let text_byte = Bytes::from(text_owned.as_bytes()); let mut online_users = online_users.lock().await; online_users.send_to_user(target_user, text_byte).await; } Ok(()) }
被调用方代码(send_to_user函数)
pub async fn send_to_user(&mut self, name: &str, content: Bytes) -> io::Result<()> { let target_user = self .list .get_mut(name) .ok_or(io::Error::new(io::ErrorKind::NotConnected, name.clone()))?; target_user.send(content).await?; Ok(()) }
错误信息
error[E0597]: `text_owned` does not live long enough --> server/src/handler.rs:28:37 | 28 | let text_byte = Bytes::from(text_owned.as_bytes()); | ------------^^^^^^^^^^^^^^^^^^^^^- | | | | | borrowed value does not live long enough | argument requires that `text_owned` is borrowed for `'static` ... 31 | } | - `text_owned` dropped here while still borrowed
问题成因
- 调用
Bytes::from(text_owned.as_bytes())时,as_bytes()返回的&[u8]生命周期与text_owned绑定。Bytes::from针对&[u8]的实现会创建一个引用型Bytes,该Bytes内部持有原切片的引用,因此要求原切片的生命周期必须为'static——否则当text_owned被销毁后,Bytes内部的引用会变成悬垂引用。 - 常见误解是认为
await会保证text_owned存活到send_to_user执行完毕,但Rust的生命周期检查是编译期静态分析,不会考虑运行时的执行顺序。编译器仅能看到text_owned在代码块结束时被销毁,而text_byte(持有对它的引用)可能在其销毁后仍存在,因此触发生命周期错误。
修复方法
方法1:直接从String创建Bytes(推荐,零成本)
Bytes支持直接从String创建,此时会接管String的底层内存,无需复制数据,也不再依赖原String的生命周期:
pub async fn send_msg(online_users: Arc<Mutex<OnlineUsers>>, msg: &Message, from: &str) -> io::Result<()> { let target_user = msg.args.get(0).ok_or(io::Error::from(io::ErrorKind::InvalidInput))?; if let Content::Text(ref text) = msg.content { let text_owned = text.clone(); let text_byte = Bytes::from(text_owned); // 直接转移String所有权到Bytes let mut online_users = online_users.lock().await; online_users.send_to_user(target_user, text_byte).await?; // 补充错误处理 } Ok(()) }
方法2:复制切片内容到Bytes
如果不想转移String的所有权,可以使用Bytes::copy_from_slice将切片内容复制到Bytes的内部内存中,生成一个独立的Bytes实例:
pub async fn send_msg(online_users: Arc<Mutex<OnlineUsers>>, msg: &Message, from: &str) -> io::Result<()> { let target_user = msg.args.get(0).ok_or(io::Error::from(io::ErrorKind::InvalidInput))?; if let Content::Text(ref text) = msg.content { let text_byte = Bytes::copy_from_slice(text.as_bytes()); // 复制切片内容 let mut online_users = online_users.lock().await; online_users.send_to_user(target_user, text_byte).await?; } Ok(()) }
内容的提问来源于stack exchange,提问作者realzhujunhao
相关产品推荐
相关产品推荐

