代码之家  ›  专栏  ›  技术社区  ›  Ahmet Yazıcı

在没有新堆分配的情况下将Vec<T>映射到Vec<K>,其中size(T)>=size(K)

  •  2
  • Ahmet Yazıcı  · 技术社区  · 5 月前

    我有两个结构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的额外容量。

    1 回复  |  直到 5 月前
        1
  •  1
  •   Chayim Friedman    5 月前

    实现这一点的代码非常简单:

    pub fn map(v: Vec<T>) -> Vec<K> {
        v.into_iter().map(|v| K { k_val: v.k.k_val }).collect()
    }
    

    是的,就是这样。如果你看 on godbolt ,您将看到这不会分配。

    当然,其中涉及“魔法”。Rust标准库为 Vec -to- Vec 不尽可能分配的迭代器。当然,这不是 放心 .

    你可以通过使用不安全的代码来保证这一点,但你真的不应该有理由这样做。

    请注意,只有在对齐 K 与对齐方式相同 T ,并且大小是倍数,因为它需要匹配以进行交易。