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

Rust求助:`&`引用数据无法被可变借用的问题

Rust新手Trait对象存储问题解决

问题描述

我是Rust新手,尝试将Animal Trait对象存储到向量中时遇到了编译错误,代码和错误信息如下:

实现代码

mod TestAnimal {
    use crate::stack;

    pub trait Animal {
        fn diagnose(&self) -> Result<(), stack::service::ServiceError>;
    }

    pub struct Hospital {
        animals: Vec<Box<dyn Animal>>,
    }

    static mut HOSPITAL: Hospital = Hospital { animals: Vec::new() };

    impl Hospital {
        pub fn add_animal(&mut self, animal: Box<dyn Animal>) {
            self.animals.push(animal);
        }
    }

    pub fn get_hospital() -> &'static Hospital {
        unsafe {
            return &HOSPITAL;
        }
    }
}

#[test]
fn test_hospital() {
    pub struct Cat;
    impl TestAnimal::Animal for Cat {
        fn diagnose(&self) -> Result<(), stack::service::ServiceError> {
            return Ok(());
        }
    }

    TestAnimal::get_hospital().add_animal(Box::new(Cat {}));
}

错误信息

error[E0596]: cannot borrow data in a `&` reference as mutable
  --> src/main.rs:45:5
   |
45 |     TestAnimal::get_hospital().add_animal(Box::new(Cat {}));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable

解决方案

错误核心原因:get_hospital()返回的是不可变引用&'static Hospital,但add_animal方法需要可变引用&mut self,Rust的借用规则禁止通过不可变引用调用可变方法。另外,直接使用static mut属于不安全操作,存在线程安全和数据竞争风险,不推荐。

方案1:临时修复(保留static mut,不推荐)

修改get_hospital返回可变引用,调用时必须包裹在unsafe块中:

// 修改TestAnimal模块中的get_hospital
pub unsafe fn get_hospital_mut() -> &'static mut Hospital {
    &mut HOSPITAL
}

// 测试函数中调用
#[test]
fn test_hospital() {
    pub struct Cat;
    impl TestAnimal::Animal for Cat {
        fn diagnose(&self) -> Result<(), stack::service::ServiceError> {
            Ok(())
        }
    }

    unsafe {
        TestAnimal::get_hospital_mut().add_animal(Box::new(Cat {}));
    }
}

方案2:安全全局状态实现(推荐)

使用once_cell crate创建线程安全的全局可变状态,避免unsafe代码:

  1. 在Cargo.toml添加依赖:once_cell = "1.19.0"
  2. 修改TestAnimal模块:
mod TestAnimal {
    use crate::stack;
    use once_cell::sync::Lazy;
    use std::sync::Mutex;

    pub trait Animal {
        fn diagnose(&self) -> Result<(), stack::service::ServiceError>;
    }

    pub struct Hospital {
        animals: Vec<Box<dyn Animal>>,
    }

    static HOSPITAL: Lazy<Mutex<Hospital>> = Lazy::new(|| {
        Mutex::new(Hospital { animals: Vec::new() })
    });

    impl Hospital {
        pub fn add_animal(&mut self, animal: Box<dyn Animal>) {
            self.animals.push(animal);
        }
    }

    pub fn get_hospital() -> &'static Lazy<Mutex<Hospital>> {
        &HOSPITAL
    }
}

#[test]
fn test_hospital() {
    pub struct Cat;
    impl TestAnimal::Animal for Cat {
        fn diagnose(&self) -> Result<(), stack::service::ServiceError> {
            Ok(())
        }
    }

    // 锁定Mutex获取可变引用
    let mut hospital = TestAnimal::get_hospital().lock().unwrap();
    hospital.add_animal(Box::new(Cat {}));
}

此方案既遵守Rust借用规则,又避免了static mut的安全风险,同时保证线程安全。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 09:40:42