Rust调用结构体方法修改向量两元素时遇E0499错误求解
Advent of Code Rust 开发:解决Vec中可变引用重复借用问题
我正在用Rust完成今年的AOC(Advent of Code)以学习该语言,这暴露了我对Rust的诸多不理解。我为CrateStack结构体实现了transfer方法:
pub fn transfer(&mut self, other: &mut CrateStack, num_crates: i32) { for _ in 1..num_crates { self.contents.push(other.contents.pop().unwrap()); } }
接着创建了CrateStack类型的向量:
let num_stacks = 9; let mut crates: Vec<CrateStack> = Vec::with_capacity(num_stacks); for _ in 0..num_stacks { crates.push(CrateStack::new()); }
调用transfer方法时使用:
crates[stack2 as usize].transfer(&mut crates[stack1 as usize], qty);
但Rust编译器报出错误:
error[E0499]: cannot borrow `crates` as mutable more than once at a time --> src/main.rs:54:51 | 54 | crates[stack2 as usize].transfer(&mut crates[stack1 as usize], qty); | ------ -------- ^^^^^^ second mutable borrow occurs here | | | | | first borrow later used by call | first mutable borrow occurs here
我不想舍弃结构体,希望学习正确的解决方法。
问题原因
Rust的借用检查器不允许同时对同一个Vec的两个元素进行可变借用——编译器无法静态确认stack1和stack2指向的是不同的索引,担心出现数据竞争或悬垂引用,因此直接拒绝这种写法。
解决方法
方法1:使用split_at_mut安全分离可变引用
split_at_mut是Vec提供的安全方法,能将向量切分为两个不重叠的可变切片,借此可以同时获取两个不同元素的可变引用,且不会触发借用检查错误。
示例代码:
// 先确保stack1和stack2是不同的索引(如果相同则无需转移) let stack1_idx = stack1 as usize; let stack2_idx = stack2 as usize; if stack1_idx == stack2_idx { return; } // 用split_at_mut拆分Vec let (left, right) = crates.split_at_mut(std::cmp::min(stack1_idx, stack2_idx) + 1); let (source, target) = if stack1_idx < stack2_idx { // stack1在左半部分,stack2在右半部分 (&mut left[stack1_idx], &mut right[stack2_idx - left.len()]) } else { // stack1在右半部分,stack2在左半部分 (&mut right[stack1_idx - left.len()], &mut left[stack2_idx]) }; // 调用transfer方法 target.transfer(source, qty);
方法2:调整transfer为外部函数(可选)
如果不想用split_at_mut,可以把转移逻辑从结构体方法改成独立函数,显式接收两个可变引用,但本质上还是需要借助split_at_mut或其他安全方式获取这两个引用,所以方法1更直接。
额外小提示
你当前的transfer方法循环是1..num_crates,这只会转移num_crates - 1个箱子,应该改成0..num_crates或者1..=num_crates才能转移指定数量的箱子。
内容的提问来源于stack exchange,提问作者Alan
相关产品推荐
相关产品推荐

