Rust中如何无复制实现独立栈间元素批量逆序转移?
Rust中嵌套Vec的跨栈元素转移问题
核心疑问与场景
可以拥有包含可变Vector的不可变Vector:外层Vec不可变意味着你无法添加、删除或替换内部的Vec实例,但每个内部Vec的内容依然可以修改——只要你能获取到它们的可变引用。
实际场景:用Vec<Vec<i32>>模拟栈,需要从一个栈取出N个元素并逆序推入另一个栈,原有代码编译失败:
let mut stacks: Vec<Vec<i32>>; // ... 初始化逻辑 let end = stacks[from].iter().take(count); stacks[to].extend(end); // 编译失败
失败原因
iter()返回的是不可变引用迭代器,只能读取元素,无法转移所有权(也就是无法从原栈移除元素);- 代码同时持有了
stacks的不可变借用(stacks[from].iter())和可变借用(stacks[to].extend()),违反了Rust的借用规则——即使操作的是不同内部栈,普通的索引借用会被视为对整个外层Vec的借用,触发编译错误。
无需创建中间Vec的解决方案
方法1:使用drain(推荐,安全简洁)
drain方法可以从Vec的指定范围移除元素,并返回一个拥有元素所有权的迭代器,且能被借用检查器识别为对单个内部Vec的独立可变借用,不会与其他内部Vec的借用冲突。
如果要取原栈末尾的N个元素并逆序推入目标栈:
// 计算原栈中要取出的元素起始位置 let from_len = stacks[from].len(); let start_idx = from_len - count; // 从原栈移除指定范围的元素,得到所有权迭代器 let drained_elements = stacks[from].drain(start_idx..); // 逆序迭代并推入目标栈 stacks[to].extend(drained_elements.rev());
如果不需要逆序(对应Advent of Code 2022 Day5的b部分需求),直接去掉rev()即可:
stacks[to].extend(drained_elements);
方法2:底层内存操作(unsafe,不推荐)
如果追求极致性能,可以手动通过指针操作转移元素,但需要自行保证内存安全:
use std::ptr; let from_stack = &mut stacks[from]; let to_stack = &mut stacks[to]; let from_len = from_stack.len(); let start_idx = from_len - count; // 为目标栈预留足够空间 to_stack.reserve(count); unsafe { // 复制元素到目标栈末尾(移动语义,无拷贝) ptr::copy_nonoverlapping( from_stack.as_ptr().add(start_idx), to_stack.as_mut_ptr().add(to_stack.len()), count, ); // 更新目标栈的长度 to_stack.set_len(to_stack.len() + count); // 截断原栈,移除已转移的元素 from_stack.set_len(start_idx); }
此方法跳过了迭代器的开销,但使用unsafe块,必须确保count <= from_len,否则会触发内存越界。
内容的提问来源于stack exchange,提问作者MrPurpleStreak
相关产品推荐
相关产品推荐

