如何在Rust中创建泛型零大小类型(ZST)的实例?
如何安全创建零大小类型(ZST)的实例?
问题背景
我需要在泛型代码中,当类型参数T是零大小类型(ZST)时创建其实例,同时要严格避免未定义行为(UB):
- 排除《Rustonomicon》中
ptr::read(NonNull::<T>::dangling().as_ptr())的方案,该代码存在UB风险 - 也不使用
std::mem::MaybeUninit::<T>::uninit().assume_init(),同样存在UB风险
核心需求是适配所有ZST类型:
- 无论该类型是否实现
Defaulttrait - 覆盖空结构体(
struct Zst;、struct Zst{})、空元组(())、空或单值枚举(enum Zst;、enum Zst { TheOnlyValue })、空数组([u8; 0])及各类组合类型
最终要在如下泛型迭代器实现中完成逻辑:
impl<T> Iterator for RawIter<T> { type Item = T; fn next(&mut self) -> Option<Self::Item> { if size_of::<T>() == 0 { // 这里需要返回T的实例 Some(???); } // 非ZST的逻辑... } }
解决方案:使用std::mem::zeroed
优先选择std::mem::zeroed::<T>(),它写法简洁且对所有ZST安全。
为什么zeroed对ZST安全?
零大小类型不占用任何内存空间,zeroed不需要写入实际数据。Rust编译器会将ZST的zeroed调用优化为直接返回合法实例——因为ZST的所有可能实例语义等价(无状态差异),零初始化的结果完全符合类型的合法值要求,不存在UB风险。
最终实现代码
将迭代器中的占位符替换为zeroed即可:
use std::mem::{size_of, zeroed}; impl<T> Iterator for RawIter<T> { type Item = T; fn next(&mut self) -> Option<Self::Item> { if size_of::<T>() == 0 { // 安全创建ZST实例 Some(unsafe { zeroed() }) } else { // 非ZST类型的处理逻辑,示例返回None None } } }
适配验证
这个实现可以处理所有目标ZST类型:
- 空元组
():zeroed()返回合法的()实例 - 空结构体
struct Zst;:直接返回该结构体的唯一实例 - 单值枚举
enum Zst { Only }:返回枚举的唯一有效变体 - 空数组
[u8; 0]:返回合法的空数组实例
注意事项
zeroed需要包裹在unsafe块中,但对于ZST场景,这个unsafe是安全的——既不存在内存初始化问题,也不会违反任何类型的不变量。
内容的提问来源于stack exchange,提问作者Robin Kuzmin
相关产品推荐
相关产品推荐

