You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在不分配新堆内存的情况下将Vec<T>映射为Vec<K>(size(T)≥size(K))

无堆分配将Vec转换为Vec的实现

给定以下Rust结构体,其中T的内存大小(12字节)大于K(8字节),且T的第一个字段就是K:

struct K {
    k_val: u64,
}

struct T {
    k: K,
    t_val: u32,
}

需要在不进行任何堆内存分配的前提下,将Vec<T>转换为Vec<K>,利用原Vec的内存空间,仅通过类型转换调整指针、长度和容量的计算逻辑。

可行性分析

  • Rust默认结构体布局(无#[repr]修饰)下,字段按声明顺序排列并自动对齐。这里T的第一个字段是K,因此每个T实例的起始地址完全对应其内部k字段的起始地址,内存布局与K完全兼容。
  • 原Vec<T>的总内存字节数为容量 × size_of::<T>(),转换为Vec<K>后,长度与原Vec一致(每个T对应一个K),新容量由总字节数除以size_of::<K>()得到,末尾剩余的垃圾字节可作为Vec的额外容量保留,不会被访问到。

实现代码

要完成这个转换需要使用unsafe代码,直接操作Vec的底层组件以绕过安全检查:

use std::mem;

struct K {
    k_val: u64,
}

struct T {
    k: K,
    t_val: u32,
}

fn vec_t_to_vec_k(mut vec_t: Vec<T>) -> Vec<K> {
    // 编译期强制验证内存布局兼容性
    static_assert!(mem::offset_of!(T, k) == 0);
    static_assert!(mem::align_of::<K>() <= mem::align_of::<T>());

    let len = vec_t.len();
    // 计算原Vec的总字节容量
    let total_bytes = vec_t.capacity() * mem::size_of::<T>();
    // 新Vec的容量为总字节数能容纳的K实例数量
    let new_capacity = total_bytes / mem::size_of::<K>();

    // 取出原Vec的底层指针,同时阻止原Vec的drop逻辑释放内存
    let ptr = vec_t.as_mut_ptr();
    mem::forget(vec_t);

    // 重新解释指针类型,构造新的Vec<K>
    unsafe { Vec::from_raw_parts(ptr as *mut K, len, new_capacity) }
}

// 测试示例
fn main() {
    let vec_t = vec![
        T { k: K { k_val: 1 }, t_val: 10 },
        T { k: K { k_val: 2 }, t_val: 20 },
        T { k: K { k_val: 3 }, t_val: 30 },
    ];

    let vec_k = vec_t_to_vec_k(vec_t);

    assert_eq!(vec_k.len(), 3);
    assert_eq!(vec_k[0].k_val, 1);
    assert_eq!(vec_k[1].k_val, 2);
    assert_eq!(vec_k[2].k_val, 3);
}

注意事项

  • 布局兼容性:必须保证T的第一个字段是K,且两者的对齐要求满足(代码中已通过static_assert!在编译期验证),若修改结构体布局(如添加#[repr(packed)]或调整字段顺序),转换会触发未定义行为。
  • 内存安全:使用mem::forget(vec_t)是为了避免原Vec释放内存,否则新Vec会指向已回收的内存空间。
  • 垃圾字节:转换后的Vec末尾存在未使用的垃圾字节,但由于Vec的长度被限制为原Vec的长度,这些字节不会被访问,仅作为额外容量存在。

内容的提问来源于stack exchange,提问作者Ahmet Yazıcı

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 04:08:20