在 Rust 中,Vec 和 VecDeque 中的方法
extend
和 drain
是复制项目的内容,还是像列表一样移动项目?
考虑到
reserve
预留已被提前调用,并且 Vec/VecDeque 已经有用于元素的空间。
编辑:为了澄清,下面的代码在内存级别会发生什么?内容是从 Vec 复制到 VecDeque,还是只是指针发生了变化,例如在链表中删除/插入?
let mut a: Vec<i32> = (0..10).collect();
let mut b: VecDeque<i32> = VecDeque::new();
b.reserve(10);
b.extend(a.drain(..));
a
和b
的数据位于内存中的固定位置。因为 b
已经有足够的容量,所以不会发生 b
的重新分配。
数据本身将从
a
内存复制到 b
,并且 a
之后将被标记为空。
为了演示,这里有一个小程序,显示了
Vec
在这个过程中的内部状态:
use std::fmt::Debug;
macro_rules! dbg_vec {
($v: ident) => {
dbg_vec_impl(stringify!($v), &$v);
};
}
fn dbg_vec_impl<T: Debug>(name: &str, v: &Vec<T>) {
println!(
"Vec '{}': ({:p}, {}, {})",
name,
v.as_ptr(),
v.len(),
v.capacity()
);
println!(" Real content: {:?}", v);
unsafe {
println!(
" Memory content: {:?}",
std::slice::from_raw_parts(v.as_ptr(), v.capacity())
)
};
}
fn main() {
let mut a: Vec<i32> = (0..10).collect();
let mut b: Vec<i32> = Vec::new();
dbg_vec!(a);
dbg_vec!(b);
b.reserve(10);
println!("\nb.reserve(10);\n");
dbg_vec!(a);
dbg_vec!(b);
b.extend(a.drain(..));
println!("\nb.extend(a.drain(..))\n");
dbg_vec!(a);
dbg_vec!(b);
a.shrink_to_fit();
b.shrink_to_fit();
println!("\nshrink_to_fit()\n");
dbg_vec!(a);
dbg_vec!(b);
}
Vec 'a': (0x1e932d5deb0, 10, 10)
Real content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Memory content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Vec 'b': (0x4, 0, 0)
Real content: []
Memory content: []
b.reserve(10);
Vec 'a': (0x1e932d5deb0, 10, 10)
Real content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Memory content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Vec 'b': (0x1e932d5dd60, 0, 10)
Real content: []
Memory content: [5439557, 5505099, 5242959, 7667773, 6553710, 6684773, 7209065, 6553701, 5177344, 3997779]
b.extend(a.drain(..))
Vec 'a': (0x1e932d5deb0, 0, 10)
Real content: []
Memory content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Vec 'b': (0x1e932d5dd60, 10, 10)
Real content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Memory content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
shrink_to_fit()
Vec 'a': (0x4, 0, 0)
Real content: []
Memory content: []
Vec 'b': (0x1e932d5dd60, 10, 10)
Real content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Memory content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Vec
和VecDeque
不是链表,也不是操作表链表。它们在内存中是连续的,所以是的,会发生按位复制。复制的语义可能是复制,也可能是移动,具体取决于类型是否实现 Copy
。