Rust中如何更简洁地在嵌套Vec间移动指定元素?
Rust 向量元素批量移动优化方案
问题背景
初始代码:
let mut stacks = vec![ vec!['A', 'B'], vec!['C', 'D', 'E', 'F'], ]; println!("vec: {:?}", stacks);
运行输出:
vec: [['A', 'B'], ['C', 'D', 'E', 'F']]
需求:将第二个子Vec末尾的'E'和'F'移动到第一个子Vec中,预期输出:
vec: [['A', 'B', 'E', 'F'], ['C', 'D']]
现有实现依赖临时Vec:
let col_from = 1; let col_to = 0; let n_to_move = 2; let len = stacks[col_from].len(); let crates = stacks[col_from].drain(len - n_to_move..); let mut temp = Vec::new(); temp.extend(crates); stacks[col_to].extend(temp); println!("vec: {:?}", stacks);
需要更简洁或无需临时向量的实现方式。
优化实现方案
方案一:直接消费Drain迭代器
drain方法返回的Drain迭代器可以直接被extend接收,完全不需要临时Vec中转:
let col_from = 1; let col_to = 0; let n_to_move = 2; let len = stacks[col_from].len(); // 直接用drain的结果扩展目标向量,省去临时内存分配 stacks[col_to].extend(stacks[col_from].drain(len - n_to_move..)); println!("vec: {:?}", stacks);
这段代码逻辑和原实现一致,但去掉了不必要的临时Vec,代码更紧凑,效率也更高——extend会直接迭代Drain产生的元素,没有额外的内存拷贝。
方案二:使用split_off拆分向量
如果要移动的刚好是原向量末尾的所有目标元素,split_off是更高效的选择:
let col_from = 1; let col_to = 0; let n_to_move = 2; let len = stacks[col_from].len(); // split_off会把从指定索引到末尾的元素拆分出来,原向量仅保留前半部分 let moved_elements = stacks[col_from].split_off(len - n_to_move); stacks[col_to].extend(moved_elements); println!("vec: {:?}", stacks);
split_off是Vec的内置方法,它通过调整内部的指针和长度实现拆分,不会复制元素,性能最优,代码也更直观。
方案三:Unsafe手动内存操作(仅性能敏感场景)
如果追求极致性能,可通过unsafe代码直接操作Vec的底层内存,但这种方式复杂度高,容易引入内存安全问题,非必要不建议使用:
use std::mem; let col_from = 1; let col_to = 0; let n_to_move = 2; let from_stack = &mut stacks[col_from]; let to_stack = &mut stacks[col_to]; let from_len = from_stack.len(); let start_idx = from_len - n_to_move; unsafe { // 预分配目标向量的内存空间 to_stack.reserve(n_to_move); // 移动元素到目标向量末尾 let src_ptr = from_stack.as_mut_ptr().add(start_idx); let dst_ptr = to_stack.as_mut_ptr().add(to_stack.len()); mem::copy_nonoverlapping(src_ptr, dst_ptr, n_to_move); // 更新两个向量的长度 to_stack.set_len(to_stack.len() + n_to_move); from_stack.set_len(start_idx); } println!("vec: {:?}", stacks);
使用这段代码需要确保所有指针操作的安全性,比如源和目标内存无重叠、指针有效等。
内容的提问来源于stack exchange,提问作者tmaj
相关产品推荐
相关产品推荐

