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

如何在Rust中让多个对象可变访问同一中心数据池?

问题描述

我们拥有Hello和Hi两个结构体,调用它们任意一个的方法时,需要让中心State实例的计数x自增1。

以下是初始示例代码:

struct State{
    x: i32
}
impl State {
    fn new() -> Self{
        Self {x:0}
    }
    fn plusplus(&mut self){
        self.x += 1
    }
}
struct Hello<'a>{
    s: &'a mut State
}
impl Hello<'_>{
    fn hello(&mut self){
        println!("hello");
        self.s.plusplus();
    }
}
struct Hi<'a>{
    s: &'a mut State
}
impl Hi<'_>{
    fn hi(&mut self){
        println!("hi");
        self.s.plusplus();
    }
}

fn main() {
    let mut s = State::new();
    let mut a = Hello{s:&mut s};
    let mut b = Hello{s:&mut s};
    a.hello();
    a.hello();
}

当前代码无法编译,原因是Rust的编译期借用规则不允许对同一个变量进行多次可变借用。

解决方案:无需使用unsafe

完全不需要借助unsafe关键字,Rust标准库提供了安全的内部可变性工具,可根据运行场景(单线程/多线程)选择合适的方案:

方案1:单线程场景 - 使用RefCell

RefCell是单线程下的内部可变性容器,它将借用规则的检查从编译期推迟到运行期,允许在持有不可变引用的同时修改内部数据。

修改后的代码:

use std::cell::RefCell;

struct State {
    x: i32
}

impl State {
    fn new() -> Self {
        Self { x: 0 }
    }
    fn plusplus(&mut self) {
        self.x += 1;
        println!("当前计数: {}", self.x);
    }
}

struct Hello<'a> {
    s: &'a RefCell<State>
}

impl Hello<'_> {
    fn hello(&self) {
        println!("hello");
        // 通过borrow_mut()获取可变引用,运行时检查借用合法性
        self.s.borrow_mut().plusplus();
    }
}

struct Hi<'a> {
    s: &'a RefCell<State>
}

impl Hi<'_> {
    fn hi(&self) {
        println!("hi");
        self.s.borrow_mut().plusplus();
    }
}

fn main() {
    let s = RefCell::new(State::new());
    // 可以创建多个共享同一个RefCell的实例
    let a = Hello { s: &s };
    let b = Hi { s: &s };
    
    a.hello();
    a.hello();
    b.hi();
}

方案2:多线程场景 - 使用Arc+Mutex

如果代码需要在多线程环境下运行,Mutex可以提供互斥锁保证同一时间只有一个线程能修改State,配合Arc实现多线程下的共享所有权,完全消除竞态条件。

修改后的代码:

use std::sync::{Arc, Mutex};
use std::thread;

struct State {
    x: i32
}

impl State {
    fn new() -> Self {
        Self { x: 0 }
    }
    fn plusplus(&mut self) {
        self.x += 1;
        println!("当前计数: {}", self.x);
    }
}

struct Hello {
    s: Arc<Mutex<State>>
}

impl Hello {
    fn hello(&self) {
        println!("hello");
        // 获取锁,同一时间只有一个线程能进入临界区
        let mut state = self.s.lock().unwrap();
        state.plusplus();
    }
}

struct Hi {
    s: Arc<Mutex<State>>
}

impl Hi {
    fn hi(&self) {
        println!("hi");
        let mut state = self.s.lock().unwrap();
        state.plusplus();
    }
}

fn main() {
    let s = Arc::new(Mutex::new(State::new()));
    
    // 通过Arc::clone复制共享所有权
    let a = Hello { s: Arc::clone(&s) };
    let b = Hi { s: Arc::clone(&s) };
    
    // 在不同线程中调用方法
    let handle1 = thread::spawn(move || {
        a.hello();
        a.hello();
    });
    
    let handle2 = thread::spawn(move || {
        b.hi();
        b.hi();
    });
    
    handle1.join().unwrap();
    handle2.join().unwrap();
}
总结

无论是单线程还是多线程场景,都可以通过Rust标准库提供的安全工具解决问题,完全不需要使用unsafe代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 14:22:39