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

Rust中使用Rc<RefCell>实现树插入的可变借用错误解决

修正Rc实现二叉树插入的问题

你遇到的核心问题是Rc的借用规则冲突:循环中持有不可变借用(borrow())的同时尝试获取可变引用,违反了Rust的借用检查;另外因为Node的字段是私有,直接访问需要通过可变借用的方式。

下面是修正后的完整代码,关键修改点会在代码后说明:

use std::cell::RefCell;
use std::cmp::Ordering;
use std::rc::Rc;
use std::fmt;

#[derive(Debug, Clone)]
pub(crate) struct TreeBox<T> {
    root: Option<Box<NodeBox<T>>>,
}

#[derive(Debug, Clone)]
struct NodeBox<T> {
    value: T,
    left: Option<Box<NodeBox<T>>>,
    right: Option<Box<NodeBox<T>>>,
}

impl<T: Ord> TreeBox<T> {
    fn new() -> Self {
        Self { root: None }
    }

    pub fn insert(&mut self, value: T) -> bool {
        let mut node = &mut self.root;

        while let Option::Some(current_node) = node {
            match current_node.value.cmp(&value) {
                Ordering::Less => node = &mut current_node.right,
                Ordering::Equal => return false,
                Ordering::Greater => node = &mut current_node.left,
            }
        }

        *node = Option::Some(Box::new(NodeBox {
            value,
            left: Option::None,
            right: Option::None,
        }));

        return true;
    }
}

#[derive(Debug, Clone)]
pub(crate) struct Tree<T> {
    root: Option<Rc<RefCell<Node<T>>>>,
}

#[derive(Debug, Clone, PartialEq)]
struct Node<T> {
    value: T,
    left: Option<Rc<RefCell<Node<T>>>>,
    right: Option<Rc<RefCell<Node<T>>>>,
}

impl<T: Ord + fmt::Debug> Tree<T> {
    fn new() -> Self {
        Self { root: None }
    }

    pub fn insert(&mut self, value: T) -> bool {
        let mut node = &mut self.root;

        loop {
            match node {
                None => break,
                Some(current_rc) => {
                    // 先获取不可变借用比较值,然后立即释放
                    let current_ref = current_rc.borrow();
                    let cmp = current_ref.value.cmp(&value);
                    // 手动drop释放不可变借用,避免后续可变借用冲突
                    drop(current_ref);

                    match cmp {
                        Ordering::Equal => return false,
                        Ordering::Less => {
                            // 获取可变借用访问right字段
                            let mut current_mut = current_rc.borrow_mut();
                            node = &mut current_mut.right;
                        }
                        Ordering::Greater => {
                            // 获取可变借用访问left字段
                            let mut current_mut = current_rc.borrow_mut();
                            node = &mut current_mut.left;
                        }
                    }
                }
            }
        }

        *node = Some(Rc::new(RefCell::new(Node {
            value,
            left: None,
            right: None,
        })));

        true
    }
}

fn main() {
    let mut tree_box = TreeBox::new();
    tree_box.insert(1);
    tree_box.insert(2);
    tree_box.insert(3);

    let mut tree = Tree::new();
    tree.insert(1);
    tree.insert(2);
    tree.insert(3);

    println!("TreeBox: {:?}", tree_box);
    println!("Tree: {:?}", tree);
}

关键修改说明:

  1. 调整借用生命周期:在循环中,先通过borrow()获取不可变引用比较值,然后用drop()手动释放这个借用,确保后续获取可变借用时不会冲突。
  2. 正确访问私有字段:使用borrow_mut()获取节点的可变引用,通过这个可变引用来访问left和right字段,解决私有字段无法直接访问的问题。
  3. 重构循环逻辑:把原while let改成loop+match,更清晰地处理None和Some分支,避免借用范围混乱。

运行修正后的代码,Tree结构的插入逻辑会和TreeBox一致,正常构建二叉树。

内容的提问来源于stack exchange,提问作者Danilo Souza Morães

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 16:00:53