我有两个结构体T和K,并且T的大小大于或等于K。假设如下:
struct T {
k: K,
t_val: u32,
}
struct K {
k_val: u64,
}
我想将 Vec 映射到 Vec,而不需要任何新的堆分配。这应该是最佳可能的,因为映射的 Vec 肯定比 Vec 需要更少的内存,因为 T 是 12 字节,K 是 8 字节,并且类型只是用来计算偏移量。这是我想象的样子:
*ptr -> [12(K) | 12(K) | 12(K)]
|
iter_k
iter_t
*ptr -> [8(T) | 4(garbage) | 12(K) | 12(K)]
| |
iter_t iter_k
*ptr -> [8(T) | 8(T) | 8(garbage) | 12(K)]
| |
iter_t iter_k
*ptr -> [8(T) | 8(T) | 8(T) | 12(garbage)]
| |
iter_t iter_k
最后 12 字节垃圾是无关紧要的,因为大小为 3,并且可以保留作为新 Vec 的额外容量。
执行此操作的代码非常简单:
pub fn map(v: Vec<T>) -> Vec<K> {
v.into_iter().map(|v| K { k_val: v.k.k_val }).collect()
}
是的,就是这样。如果你查看 godbolt,你会发现它没有分配。
当然,其中涉及*魔法*。 Rust 标准库为
Vec
-to-Vec
迭代器提供了专门化,这些迭代器尽可能不进行分配。当然,这不是保证。
您可以通过使用不安全的代码来保证这一点,但您确实没有理由这样做。