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代码:
- 在
Cargo.toml添加依赖:once_cell = "1.19.0" - 修改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
相关产品推荐
相关产品推荐

