如何同时从二维Vec中获取两个可变引用?
解决二维Vec同时获取两个可变引用的问题
你的代码触发Rust编译报错,核心原因是借用检查器无法静态证明data[1][2]和data[2][4]指向不同内存位置——哪怕我们肉眼能看出是不同元素,编译器没有能力做这个判断,因此禁止同时持有两个可变引用。
下面提供两种实现方案,优先推荐安全方案,也会给出你允许的unsafe实现:
安全方案(无需unsafe)
因为两个目标元素在不同的子Vec(不同行)中,我们可以先分别获取两行的可变引用,再从行内取元素。由于不同子Vec是独立的内存块,编译器允许同时持有它们的可变引用:
use std::default::Default; #[derive(Default, Clone, PartialEq)] struct Ele { foo: i32, bar: f32, } fn main() { let mut data: Vec<Vec<Ele>> = vec![vec![Default::default(); 100]; 100]; // 拆分出两行的可变引用,处理行索引大小关系避免借用冲突 let (row1, row2) = if 1 < 2 { let (first_part, rest) = data.split_at_mut(2); (&mut first_part[1], &mut rest[0]) } else { let (first_part, rest) = data.split_at_mut(1); (&mut rest[0], &mut first_part[1]) }; let a = &mut row1[2]; let b = &mut row2[4]; if a != b { a.foo += b.foo; b.bar += a.bar; } }
Unsafe方案(需自行保证内存安全)
如果一定要用unsafe,可以把元素转换为原始指针,再重新解引用为可变引用。但必须手动确保两个指针指向不同内存,否则会触发未定义行为:
use std::default::Default; #[derive(Default, Clone, PartialEq)] struct Ele { foo: i32, bar: f32, } fn main() { let mut data: Vec<Vec<Ele>> = vec![vec![Default::default(); 100]; 100]; // 断言确保两个元素不是同一位置,debug模式下会检查,release模式自动移除 debug_assert!(1 != 2 || 2 != 4); // 获取原始可变指针 let a_ptr = &mut data[1][2] as *mut Ele; let b_ptr = &mut data[2][4] as *mut Ele; unsafe { // 解引用指针为可变引用 let a = &mut *a_ptr; let b = &mut *b_ptr; if a != b { a.foo += b.foo; b.bar += a.bar; } } }
关键提示
- 安全方案完全符合Rust内存安全规则,无任何风险,是首选实现。
- Unsafe方案中,
debug_assert是必要的开发阶段校验,能帮你避免写出违反内存安全的代码。
内容的提问来源于stack exchange,提问作者Moold
相关产品推荐
相关产品推荐

