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

正确解开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);

底层逻辑拆解

我们一步步看为什么这样可行:

  1. state.0获取到内部的Rc<RefCell<MyState>>,Rc实现了Deref trait,会自动解引用为内部的RefCell<MyState>,所以不需要手动写*来解引用Rc。
  2. RefCell::borrow_mut()会返回一个RefMut<'_, MyState>类型,这个类型同样实现了DerefMut trait,会自动解引用成&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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 23:30:35