正确解开Rc<RefCell<T>>包装的方法
问题
我在Rust中有一个需要在代码各处传递并操作的数据结构,据我所知,最简单的默认方式是用Rc做引用计数、RefCell实现内部可变性来包装它。我自认为对这两个结构体有基础理解,写出了如下代码:
use std::rc::Rc; use std::cell::RefCell; // 需在代码各处传递并操作的核心数据结构 struct MyState { data: i32 // 示例数据 } // 用于修改示例状态的方法 impl MyState { fn modify_state(&mut self, data: i32) { self.data += data; } } // 为方便传递,用RefCell实现内部可变性、Rc做引用计数,封装为新类型 #[derive(Clone)] struct MyStateRef(Rc<RefCell<MyState>>); impl MyStateRef { fn new() -> Self { MyStateRef(Rc::new(RefCell::new(MyState{data: 0}))) } } fn main() { // 创建被Rc和RefCell包装的MyState实例 let state = MyStateRef::new(); // "state"可克隆传递,现在希望调用modify_state修改内部MyState state.0 [...???...] .modify_state(3); }
我无法让main函数的最后一行正常运行,尝试了borrow_mut、get_mut等多种组合但都失败了。我知道这涉及到Deref和DerefMut,但搞不清楚具体逻辑。有人能让最后一行正常运行并解释原因吗?
解决方案与解释
直接修复代码
把main里的最后一行改成下面这样就能正常运行:
state.0.borrow_mut().modify_state(3);
如果想让代码更优雅、避免直接暴露内部结构,可以给MyStateRef封装一个修改方法:
impl MyStateRef { fn new() -> Self { MyStateRef(Rc::new(RefCell::new(MyState{data: 0}))) } // 封装状态修改逻辑,对外提供简洁接口 fn modify_state(&self, data: i32) { self.0.borrow_mut().modify_state(data); } } // main函数里直接调用即可 state.modify_state(3);
底层逻辑拆解
我们一步步看为什么这样可行:
state.0获取到内部的Rc<RefCell<MyState>>,Rc实现了Dereftrait,会自动解引用为内部的RefCell<MyState>,所以不需要手动写*来解引用Rc。RefCell::borrow_mut()会返回一个RefMut<'_, MyState>类型,这个类型同样实现了DerefMuttrait,会自动解引用成&mut MyState,刚好匹配MyState::modify_state需要的&mut self参数。
你之前尝试get_mut失败是因为它的适用场景有限:RefCell::get_mut只有在能拿到&mut RefCell<T>(即RefCell本身是可变的)时才能调用,但这里Rc提供的是共享访问,无法直接获取&mut RefCell<T>,所以get_mut在这里用不了。
关于自动解引用的补充
Rust的自动解引用规则是为了简化代码:当你调用方法时,编译器会自动尝试对调用者进行解引用,直到找到能匹配该方法的类型。所以在这个场景下,我们不需要手动处理Rc和RefMut的解引用,编译器会帮我们自动完成。
内容的提问来源于stack exchange,提问作者Achim
相关产品推荐
相关产品推荐

