Rust中Vec与VecDeque的extend、drain方法内存处理及元素转移问询
Vec与VecDeque的extend、drain方法:复制还是移动?
核心规则
- 若元素类型实现了
Copytrait(比如i32、bool这类简单值类型),extend和drain会复制元素内容; - 若元素类型未实现
Copy(比如String、自定义结构体),则是移动元素——仅转移元素的所有权,不会复制元素的底层数据。
示例代码的内存层面分析
先看示例代码:
let mut a: Vec<i32> = (0..10).collect(); let mut b: VecDeque<i32> = VecDeque::new(); b.reserve(10); b.extend(a.drain(..));
执行步骤拆解
a.drain(..)的行为- 该方法生成一个迭代器,遍历
a的所有元素;执行后a的长度会被置为0,但底层的内存容量会保留(不会立即释放)。 - 因为
i32是Copy类型,迭代器每次返回的是原元素的副本;如果是非Copy类型,迭代器会直接转移元素的所有权(即移动元素)。
- 该方法生成一个迭代器,遍历
b.extend(...)的行为- 提前调用
b.reserve(10)后,b已分配足够容纳10个元素的内存空间,无需扩容。 - Vec的底层是单一连续内存块,而VecDeque的底层是环形缓冲区(通常也是单一连续内存块,通过头尾指针标记有效数据范围),两者内存布局完全不兼容,无法像链表那样通过修改指针批量转移元素。
- 对于
i32这类Copy元素,extend会把迭代器提供的每个副本,逐个复制到b的内存区域中。
- 提前调用
最终内存状态
a的长度变为0,但原内存块仍保留(可后续复用);b中存储了10个与原a元素值完全相同的i32副本。
非Copy类型的补充说明
如果元素是String这类非Copy类型:
a.drain(..)的迭代器会移动每个String的所有权(仅转移String内部的指针、长度、容量字段,不会复制字符串的实际字节数据);b.extend会把这些String逐个移动到自己的环形缓冲区中,同样不会复制字节内容,但依然是逐个处理元素,而非通过修改指针直接转移整块内存——因为Vec和VecDeque的内存布局无法直接兼容。
内容的提问来源于stack exchange,提问作者AmiguelS
相关产品推荐
相关产品推荐

