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

如何在Rust中正确将可变引用转为不可变引用?链表场景遇编译错误

问题原因

你遇到的错误源于Rust借用规则的核心限制:一旦某个值被可变借用,在该可变借用的生命周期内,任何对该值的其他借用(包括不可变)都会被禁止。

你的代码中,let c = &mut b.as_mut().unwrap().next;这一行会创建一个对b指向内容的可变借用——因为as_mut()需要获取*b的可变引用才能访问内部的next字段。这个可变借用的生命周期和变量c绑定,即使你后续将c重新赋值为不可变引用&*c,新的不可变引用仍然是从原来的可变借用派生而来的,编译器会认为原有的可变借用并未结束(因为新的不可变引用还在使用它)。

当你尝试执行let b = &*b;时,你试图对*b进行不可变借用,但此时b的可变借用(由c的派生引用维持)仍然存在,因此触发了E0502错误。

解决方案

要实现你的需求,更合理的方式是先完整构建链表,再从头遍历获取各节点的不可变引用,避免在构建过程中保留多层嵌套的可变引用:

struct Node<T> {
    val: T,
    next: Option<Box<Node<T>>>,
}

impl<T> Node<T> {
    fn new(val: T) -> Box<Node<T>> {
        Box::new(Node { val, next: None })
    }
}

fn main() {
    // 构建链表:用单个可变指针遍历完成所有节点的创建
    let mut head = Node::new(0);
    let mut current = &mut head;

    // 添加节点10
    current.next = Some(Node::new(10));
    current = current.next.as_mut().unwrap();

    // 添加节点20
    current.next = Some(Node::new(20));
    current = current.next.as_mut().unwrap();

    // 添加节点30
    current.next = Some(Node::new(30));
    current = current.next.as_mut().unwrap();

    // 添加节点40
    current.next = Some(Node::new(40));

    // 遍历链表,获取各中间节点的不可变引用
    let a_node = head.next.as_ref().unwrap();
    let b_node = a_node.next.as_ref().unwrap();
    let c_node = b_node.next.as_ref().unwrap();

    println!(
        "a is {}, b is {}, c is {}",
        a_node.val, b_node.val, c_node.val
    );
}

这种方式的优势在于:

  • 构建阶段仅使用一个可变指针current,所有临时可变借用都会在每次遍历后自动结束,不会留下长期的借用冲突隐患。
  • 构建完成后,整个链表的所有权完全由head持有,此时可以安全地获取任意数量的不可变引用,符合Rust的借用规则。

如果一定要保留构建过程中的节点引用,可以使用RefCell来实现内部可变性,但这会引入运行时开销,对于简单链表场景来说没必要。上面的方案是最符合Rust设计哲学的实现方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 20:35:18