Rust中如何将&[&mut Self]转换为&[(&mut Self, MappedMemoryRange)]
解决Rust中MappedMemory trait默认实现的引用所有权错误
问题背景
定义了如下MappedMemory trait和MappedMemoryRange结构体:
pub trait MappedMemory { fn range(&self) -> MappedMemoryRange; fn flush(&mut self); fn flush_range(&mut self, range: MappedMemoryRange); fn flush_ranges(&mut self, ranges: &[MappedMemoryRange]); fn flush_multiple(memories: &[&mut Self]); fn flush_multiple_ranges(memories: &[(&mut Self, MappedMemoryRange)]); } pub struct MappedMemoryRange { pub offset: u64, pub size: usize }
尝试为flush_multiple编写默认实现,将&[&mut Self]转换为&[(&mut Self, MappedMemoryRange)]后调用flush_multiple_ranges,代码如下:
let memories_and_ranges: Vec<(&mut Self, MappedMemoryRange)> = memories .into_iter() .map(|m| (*m, m.range())) .collect();
触发以下错误:
error[E0507]: cannot move out of `*m` which is behind a shared reference --> crates\xyz\src\objects\memory.rs:44:23 | 44 | .map(|m| (*m, m.range())) | ^^ move occurs because `*m` has type `&mut Self`, which does not implement the `Copy` trait
错误原因
memories的类型是&[&mut Self],调用into_iter()后得到的迭代器元素是&&mut Self(对可变引用的共享引用)。尝试*m会试图将内部的&mut Self从共享引用中移出,但&mut Self并未实现Copy trait,Rust不允许这种移动操作——因为共享引用背后的数据不能被随意移动,否则会破坏借用规则。
解决方案
不需要移动&mut Self,而是通过重新借用的方式获取合法的&mut Self引用,有两种清晰的实现方式:
方式1:使用AsMut::as_mut()方法
AsMut trait为&&mut T提供了默认实现,调用as_mut()可以安全地获取内部的&mut T引用:
fn flush_multiple(memories: &[&mut Self]) { let memories_and_ranges: Vec<(&mut Self, MappedMemoryRange)> = memories .iter() .map(|m| (m.as_mut(), m.range())) .collect(); Self::flush_multiple_ranges(&memories_and_ranges); }
方式2:显式双重解引用后重新借用
通过&mut **m显式完成双重解引用(先得到Self,再创建可变引用),效果和as_mut()一致:
fn flush_multiple(memories: &[&mut Self]) { let memories_and_ranges: Vec<(&mut Self, MappedMemoryRange)> = memories .iter() .map(|m| (&mut **m, m.range())) .collect(); Self::flush_multiple_ranges(&memories_and_ranges); }
两种方式都遵循了Rust的借用规则:没有移动原有引用,只是创建了临时的可变借用,供flush_multiple_ranges使用。
内容的提问来源于stack exchange,提问作者Rick de Water
相关产品推荐
相关产品推荐

