Rust中循环引用的构建优化方案咨询
Rust 不可变父子循环引用的轻量实现
问题场景
在C++中,我通过以下代码实现了不可变的父子循环引用:
#include <memory> #include <iostream> struct Parent; struct Child; struct Parent { std::shared_ptr<const Child> child; }; struct Child { std::weak_ptr<const Parent> parent; }; auto makeStructs() -> std::shared_ptr<const Parent> { auto parent = std::make_shared<Parent>(); parent->child = std::make_shared<const Child>(parent); return parent; }
初始化完成后,parent和child始终保持不可变,其他组件可通过共享指针安全引用它们。
但在Rust中,我当前的实现不得不引入RefCell和Option——这两者在初始化完成后就不再需要,却带来了不必要的运行时开销和代码复杂度:
use std::rc::{Rc, Weak}; use std::cell::RefCell; pub struct Parent { child : Option<Rc<Child>> } pub struct Child { parent: Weak<RefCell<Parent>> } pub fn make_structs() -> Rc<RefCell<Parent>> { let parent = Rc::new(RefCell::new(Parent{child: None})); parent.borrow_mut().child = Some(Rc::new(Child {parent : Rc::downgrade(&parent)})); return parent; }
我希望实现更轻量化的版本,不需要RefCell和Option,结构如下:
use std::rc::{Rc, Weak}; pub struct Parent { child : Rc<Child> } struct Child { parent: Weak<Parent> } pub fn make_structs() -> Rc<Parent> { // 需要实现的逻辑 }
优化实现
可以借助Rc::get_mut方法(仅当Rc的引用计数为1时允许获取可变引用),结合临时占位的方式完成初始化,完全避免RefCell和Option的使用:
use std::rc::{Rc, Weak}; pub struct Parent { child: Rc<Child>, } pub struct Child { parent: Weak<Parent>, } pub fn make_structs() -> Rc<Parent> { // 创建临时Parent实例,用空Weak的Child占位(后续会替换) let mut parent = Rc::new(Parent { child: unsafe { Rc::new_unchecked(Child { parent: Weak::new() }) }, }); // 创建持有正确Parent Weak引用的Child let child = Rc::new(Child { parent: Rc::downgrade(&parent), }); // 此时parent引用计数为1,安全获取可变引用替换child字段 if let Some(parent_mut) = Rc::get_mut(&mut parent) { parent_mut.child = child; } parent }
关键说明
- 安全性:
Rc::get_mut的使用是安全的——初始化阶段parent仅被当前作用域持有,引用计数为1,没有其他共享持有者,因此可以安全修改其内部字段。 - 无额外开销:初始化完成后,
Parent和Child都是完全不可变的结构,没有RefCell的运行时借用检查,也没有Option的分支判断开销。 - 临时不安全操作:
Rc::new_unchecked只是临时占位用,后续立刻被正确的Child实例替换,不会产生任何安全风险。
如果不想使用unsafe代码,也可以引入once_cell库的Lazy类型来延迟初始化,但上述原生实现是最轻量化的方案。
内容的提问来源于stack exchange,提问作者user4218502
相关产品推荐
相关产品推荐

