Rust中抽象可变/不可变引用以消除代码重复
消除Rust代码中可变/不可变引用的重复逻辑方案
问题代码
pub struct Memory { layout: MemoryLayout, rom: Vec<u8>, ram: Vec<u8>, } impl Memory { pub fn get_mem_vec_ref(&self, address: u32) -> Result<&Vec<u8>, RiscvError> { // ... let mem_vec_ref = match address { addr if (rom_start..rom_end).contains(&addr) => Ok(&self.rom), addr if (ram_start..ram_end).contains(&addr) => Ok(&self.ram), addr => Err(RiscvError::MemoryAlignmentError(addr)), }?; return Ok(mem_vec_ref); } pub fn get_mem_vec_mut_ref(&mut self, address: u32) -> Result<&mut Vec<u8>, RiscvError> { // ... let mem_vec_ref = match address { addr if (rom_start..rom_end).contains(&addr) => Ok(&mut self.rom), addr if (ram_start..ram_end).contains(&addr) => Ok(&mut self.ram), addr => Err(RiscvError::MemoryAlignmentError(addr)), }?; return Ok(mem_vec_ref); } }
解决方案:提取重复逻辑
两个公开函数的核心差异仅在于返回的引用类型(可变/不可变),地址匹配逻辑完全一致,最直接的消除重复方式是用宏复用匹配逻辑,实现简单且直观:
// 定义宏复用内存区域匹配逻辑 macro_rules! match_memory_region { ($self:expr, $address:expr, $rom_ref:expr, $ram_ref:expr) => { { let rom_start = $self.layout.rom_start; let rom_end = $self.layout.rom_end; let ram_start = $self.layout.ram_start; let ram_end = $self.layout.ram_end; match $address { addr if (rom_start..rom_end).contains(&addr) => Ok($rom_ref), addr if (ram_start..ram_end).contains(&addr) => Ok($ram_ref), addr => Err(RiscvError::MemoryAlignmentError(addr)), } } }; } impl Memory { pub fn get_mem_vec_ref(&self, address: u32) -> Result<&Vec<u8>, RiscvError> { // ... 保留原有的前置逻辑 match_memory_region!(self, address, &self.rom, &self.ram) } pub fn get_mem_vec_mut_ref(&mut self, address: u32) -> Result<&mut Vec<u8>, RiscvError> { // ... 保留原有的前置逻辑 match_memory_region!(self, address, &mut self.rom, &mut self.ram) } }
如果偏好泛型实现,也可以拆分出两个私有辅助函数(分别处理可变/不可变引用),将重复的匹配逻辑抽离,公开函数直接调用即可。
Box/RefCell是否适用?
- Box:是堆分配智能指针,仅用于管理内存分配位置,和消除逻辑重复完全无关,无法解决问题。
- RefCell:用于实现内部可变性,允许在持有不可变引用时修改内部数据,但这里的需求是区分外部的可变/不可变引用,不需要绕过Rust的借用规则,使用RefCell会增加不必要的运行时开销,完全不适用。
内容的提问来源于stack exchange,提问作者Tony I.
相关产品推荐
相关产品推荐

