Rust中非零大小值(non-zero-sized values)的具体定义是什么
Rust中非零大小值(non-zero-sized values)的含义与判定标准
通用概念下的判定规则
Rust中所有类型的内存大小在编译期即可确定,可通过std::mem::size_of::<T>()获取类型对应的字节数,判定逻辑非常明确:
- 若
size_of::<T>() > 0,则该类型的所有值都属于非零大小值 - 若
size_of::<T>() == 0,则对应类型为零大小类型(ZST, Zero-Sized Type),其值为零大小值
常见的非零大小值类别
- 所有基础原生类型:包括
u8/i32/f64等数值类型、bool类型、字符类型char等,这类类型的大小都是固定的正整数 - 包含至少一个非零大小字段的结构体、元组、联合体:比如
struct Account { uid: u64, balance: f32 },哪怕只包含一个非零大小字段,整个类型的大小都会大于0 - 所有指针、引用、常规智能指针类型:包括
&T/&mut T引用、裸指针*const T/*mut T、String、Vec<T>等,这类类型本身的栈上元数据大小为正(64位平台下普通指针为8字节,带长度/容量的胖指针、集合类型元数据大小更高) - 固定长度数组、切片胖指针:比如长度非0的数组
[u8; 128]大小为对应元素长度乘元素类型大小,&[u8]这类切片胖指针在64位平台下大小为16字节(数据指针+长度),均属于非零大小 - 带关联值的枚举、多无字段变体的枚举:前者因为变体携带非零大小的关联值自然大小为正;后者(比如
enum Direction { Up, Down, Left, Right })虽然所有变体都没有关联值,但编译器需要至少1字节空间区分不同变体,因此大小为1,同样属于非零大小值
容易踩的判定误区
很多人会把多无字段变体的枚举错判为零大小类型,实际上这类枚举需要至少1字节空间存储变体标记,属于非零大小值。
真正的零大小类型只有以下几类:
- 单元值
()、无字段的单元结构体(比如struct Marker;) - 没有任何变体的never类型
! - 所有字段均为零大小类型的结构体、元组、枚举变体
除此之外的所有类型,均属于非零大小类型,对应值为非零大小值。
std::boxed::Box文档上下文的对应逻辑
文档中“非零大小值将使用Global allocator完成内存分配”的表述,完全遵循上述通用大小判定规则,Box针对两类值的处理逻辑有明确差异:
- 若Box包裹的是零大小值,构造和析构全程不会调用全局分配器的申请、释放接口:零大小值不需要占用实际可读写的内存空间,编译器会直接把Box的内部指针处理为满足类型对齐要求的悬空标记地址,全程无分配开销
- 若Box包裹的是非零大小值,构造时会向全局分配器申请匹配类型大小、对齐要求的堆内存块,将值写入该块内存;Box离开作用域析构时,会调用全局分配器的释放接口归还这块内存,也就是文档描述的标准分配流程。
内容的提问来源于stack exchange,提问作者Roman Mahotskyi
相关产品推荐
相关产品推荐

