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

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移到循环外,也试过在内部添加作用域块,但都没有解决问题。


错误原因

核心问题在于生命周期绑定与引用存活时间不匹配:

  1. guard是RwLockReadGuard类型,持有对next字段的锁,其生命周期仅限于当前循环迭代的loop块内部,迭代结束时会被销毁并释放锁。
  2. val是&Option<Arc<Node>>,是对guard内部数据的引用,生命周期完全依赖于guard。
  3. next_node是从val中取出的&Arc<Node>,它的生命周期同样绑定到guard。
  4. 当你将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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 11:47:49