Rust遍历含RwLock的链表时出现“borrowed value does not live long enough”错误
Rust编译错误“borrowed value does not live long enough”分析与解决
我编写了以下Rust代码,编译时提示“borrowed value does not live long enough”错误:
use std::sync::{Arc, RwLock}; struct Node { val: RwLock<f32>, next: RwLock<Option<Arc<Node>>>, } impl Node { pub fn traverse(&self) { let mut current_node = self; loop { let guard = current_node.next.read().unwrap(); let val = &*guard; { let next_node = match val { Some(node) => node, None => break, }; println!("{:?}", *current_node.val.read().unwrap()); current_node = next_node; } } } }
编译器给出的错误信息:
| 150 | let val = &*guard; | ^^^^^ borrowed value does not live long enough ... 160 | } | - | | | `guard` dropped here while still borrowed | borrow might be used here, when `guard` is dropped and runs the `Drop` code for type `RwLockReadGuard`
我尝试过将guard和val移到循环外,也试过在内部添加作用域块,但都没有解决问题。
错误原因
核心问题在于生命周期绑定与引用存活时间不匹配:
guard是RwLockReadGuard类型,持有对next字段的锁,其生命周期仅限于当前循环迭代的loop块内部,迭代结束时会被销毁并释放锁。val是&Option<Arc<Node>>,是对guard内部数据的引用,生命周期完全依赖于guard。next_node是从val中取出的&Arc<Node>,它的生命周期同样绑定到guard。- 当你将
current_node赋值为next_node时,current_node的引用会被保留到下一次循环迭代,但此时guard已经被销毁,对应的锁已释放,这就导致current_node引用了一个失去锁保护的对象,违反了Rust的内存安全规则。
简言之:current_node的存活时间超过了它所依赖的guard的存活时间,编译器不允许这种悬空引用的风险。
解决方法
既然问题出在引用生命周期不匹配,我们可以通过克隆Arc<Node>来摆脱对guard的依赖——Arc是原子引用计数类型,克隆操作仅增加引用计数,非常轻量。
推荐方案(安全无unsafe)
调整traverse的参数为Arc<Node>,直接克隆传递节点:
use std::sync::{Arc, RwLock}; struct Node { val: RwLock<f32>, next: RwLock<Option<Arc<Node>>>, } impl Node { pub fn traverse(self: &Arc<Node>) { let mut current_node = self.clone(); loop { let guard = current_node.next.read().unwrap(); // 克隆Arc,完全摆脱对guard的引用依赖 let next_arc = match &*guard { Some(next) => next.clone(), None => break, }; println!("{:?}", *current_node.val.read().unwrap()); current_node = next_arc; } } }
备选方案(需unsafe,谨慎使用)
如果必须保持traverse接收&Node参数,可以通过Arc::from_raw/Arc::into_raw获取自身的Arc,但必须严格保证Node实例确实由Arc管理,否则会引发未定义行为:
use std::sync::{Arc, RwLock}; struct Node { val: RwLock<f32>, next: RwLock<Option<Arc<Node>>>, } impl Node { pub fn traverse(&self) { // 安全前提:self必须是被Arc持有的实例 let mut current_node = unsafe { Arc::from_raw(self) }; loop { let guard = current_node.next.read().unwrap(); let next_arc = match &*guard { Some(next) => next.clone(), None => { // 避免提前drop导致悬空,将current_node转换回原始指针 let _ = Arc::into_raw(current_node); break; } }; println!("{:?}", *current_node.val.read().unwrap()); // 替换前将旧节点转换回原始指针,防止引用计数错误 let _ = Arc::into_raw(current_node); current_node = next_arc; } } }
内容的提问来源于stack exchange,提问作者astinov
相关产品推荐
相关产品推荐

