Мне нужно избавиться от дублирования в этом коде:
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);
}
}
Как я могу абстрагироваться, используя изменяемую или неизменяемую ссылку на себя? Могут ли Box или RefCell помочь в этом случае?
Нет, он возвращает только изменяемую ссылку на внутренний вектор структуры. &self не будет работать внутри get_mem_vec_mut_ref, потому что тогда я не смогу заимствовать &mut self.rom изменчиво.

Поскольку в обоих случаях вы имеете дело со ссылками, вы можете определить общую функцию, где T будет либо &Vec<u8>, либо &mut Vec<u8>. Итак, вы можете сделать что-то вроде этого:
fn get_mem<T>(address: u32, rom: T, ram: T) -> Result<T, RiscvError> {
// ...
match address {
addr if (rom_start..rom_end).contains(&addr) => Ok(rom),
addr if (ram_start..ram_end).contains(&addr) => Ok(ram),
addr => Err(RiscvError::MemoryAlignmentError(addr)),
}
}
impl Memory {
pub fn get_mem_vec_ref(&self, address: u32) -> Result<&Vec<u8>, RiscvError> {
// ...
let mem_vec_ref = get_mem(address, &self.rom, &self.ram)?;
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 = get_mem(address, &mut self.rom, &mut self.ram)?;
return Ok(mem_vec_ref);
}
}
Теперь, очевидно, вам нужно изменить get_mem(), чтобы учесть rom_start, rom_end, ram_start, ram_end. Если вы хотите избежать необходимости передавать 100 полей в get_mem(), возможно, вместо этого стоит ввести новый тип для работы с адресами, например. что-то вроде:
struct Addr {
// ...
}
impl Addr {
fn get_mem<T>(&self, rom: T, ram: T) -> Result<T, RiscvError> {
// ...
}
}
Таким образом, когда я добавляю другой тип памяти, мне нужно будет добавить аргументы в функцию get_mem. Я хотел бы избежать этого, если это возможно.
@TonyI. Мне нужно больше контекста, чтобы дать лучшее предложение. Когда вы говорите о другом типе памяти, вы имеете в виду другой Vec<u8> в Memory или совершенно отдельный тип? Кроме того, я предполагаю, что *_start и _end связаны с Vec<u8> того же имени. Так что возможно им стоит быть вместе в 1 типе. Опять же, я могу размышлять о многом, но мне понадобится больше контекста, чтобы дать лучшие идеи. Итак, на данный момент, если вы просто хотите удалить предоставленный вами дублирующийся код, вы можете сделать это следующим образом.
Под дополнительными типами памяти я подразумеваю что-то вроде отображаемого в память адресного пространства ввода-вывода, добавленного в Memory struct. Ваше решение действительно работает хорошо, теперь, когда я думаю о добавлении 1-2 аргументов, в дальнейшем не будет больших накладных расходов. Я буду использовать его, чтобы получить +1 и принять от меня.
Изменяет ли
get_mem_vec_mut_refself?