我有一个我不明白的问题:
fn cipher_with(key: &[u8], data: &[u8]) -> Vec<u8> {
let data_len = 16;
let mut data = data.to_vec();
data.resize(data_len, 2);
let mut output = Vec::<u8>::with_capacity(data_len);
unsafe { output.set_len(data_len) }
output
}
fn main() {
let key = "blabla".as_bytes();
let data = "lorem ipsum.".as_bytes();
println!("{:?}", cipher_with(&key, &data));
}
打印:
[108,111,114,101,109,32,105,112,115,117,109,46,0,0,0,0]
但它是如何完成的?我从未将此值赋予output
。
答案 0 :(得分:5)
要向Peter's answer添加一些详细信息,请查看此注释版本:
fn cipher_with(key: &[u8], data: &[u8]) -> Vec<u8> {
let data_len = 16;
let mut data = data.to_vec();
println!("{:?}", data.as_ptr());
data.resize(data_len, 2);
println!("{:?}", data.as_ptr());
let mut output = Vec::<u8>::with_capacity(data_len);
println!("{:?}", output.as_ptr());
unsafe { output.set_len(data_len) }
output
}
0x7fa6dba27000
0x7fa6dba1e0c0
0x7fa6dba27000
创建第一个向量时,它的长度为12.当它被调整为16时,将进行新的分配并复制数据。这可能是由于分配器的实现,分配器通常将分配分块到桶中。 16将是一个合理的桶大小。
当创建第二个向量时,分配器会移回第一个向量刚刚放弃的相同指针。由于没有其他内容同时改变了这个内存,它仍然包含data
中的任何数据。
答案 1 :(得分:3)
您正在使用不安全的Rust,这会给您带来不可预测的结果。
在这种特殊情况下,您将Vec
的大小扩展为未初始化的内存。这些值已经发生在那里。
让我们看看一些代码:
let mut data = data.to_vec();
这会复制数据“lorem ipsum”。以向量的形式进入堆。
data.resize(data_len, 2); // data_len = 16
这会将Vec
的容量从12个增加到16个,在这种情况下恰好是字节。但实际上,根据我们所看到的情况,看起来实现(或可能是优化器)决定放弃第一个分配的内存范围并将数据复制到新内存更好。
let mut output = Vec::<u8>::with_capacity(data_len);
unsafe { output.set_len(data_len) }
这会创建一个新的矢量,不安全地会给它一个长度。但是你没有初始化它,所以数据将是以前的数据。
看起来data.resize()
实际上复制了值而不是仅仅删除了向量的末尾。分配output
时,它被分配了之前使用的相同内存块,这就是它包含"lorem ipsum."
的原因。