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

Rust中如何用普通引用实现子持父引用的简单父子结构

结论

  • 仅使用普通引用完全不可能实现这类循环引用结构:Rust的生命周期规则要求父节点的生命周期严格长于所有子节点,而子节点持有的父引用又反过来要求父节点生命周期不短于子节点,二者形成不可调和的生命周期矛盾;同时你在持有父节点不可变引用的同时修改父节点(插入子节点)的操作,也违反了同一时间可变/不可变引用不能共存的借用规则。
  • 即使借助unsafe也不推荐这类实现:如果用裸指针存储父引用,一旦父节点发生移动(比如所有权转移、内部Vec扩容等场景),裸指针会直接变成悬垂指针,触发未定义行为,完全违背Rust的安全设计逻辑。
  • 满足要求的最小实现可以基于Rc+Weak的组合,全程无需不安全代码,同时可以满足「无孤儿子节点」的约束。

最小可运行实现

该实现中所有子节点只能通过父节点的add_child方法创建,创建后会自动被父节点持有,不会出现孤儿子节点,同时通过弱引用避免循环引用导致的内存泄漏:

use std::rc::{Rc, Weak};
use std::cell::RefCell;

struct Parent {
    children: Vec<Rc<RefCell<Child>>>,
}

struct Child {
    parent: Weak<RefCell<Parent>>,
}

impl Parent {
    // 仅通过父节点方法创建子节点,从根源避免孤儿节点
    fn add_child(self: &Rc<RefCell<Self>>) -> Rc<RefCell<Child>> {
        let child = Rc::new(RefCell::new(Child {
            parent: Rc::downgrade(self),
        }));
        self.borrow_mut().children.push(child.clone());
        child
    }
}

fn main() {
    // 初始化被Rc包裹的父节点
    let parent = Rc::new(RefCell::new(Parent { children: vec![] }));
    // 新增子节点
    let _child1 = parent.add_child();
    let _child2 = parent.add_child();
    
    // 验证引用计数符合预期
    println!("父节点强引用计数:{},弱引用计数:{}", 
        Rc::strong_count(&parent), 
        Rc::weak_count(&parent)
    );
    // 输出:父节点强引用计数:1,弱引用计数:2
    // 说明子节点持有的是弱引用,不会导致循环内存泄漏
}

如果需要在多线程场景下使用,只需把Rc替换为Arc,RefCell替换为RwLock/Mutex即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 07:18:05