令我惊讶的是
Option<Vec<T>>
与Vec<T>
的大小相同:
fn main() {
println!(
"u128: {} -> {}",
size_of::<u128>(),
size_of::<Option<u128>>()
);
println!(
"vec: {} -> {}",
size_of::<Vec<u16>>(),
size_of::<Option<Vec<u16>>>()
);
}
评估至
u128: 16 -> 32
vec: 24 -> 24
那么
Rust 如何表示
None
的 Option<Vec>
情况?看起来正常的 Vec
的 24 个字节来自 3 个 8 字节字段:一个指针、一个字节容量和一个长度。我的猜测是它使用了 None
的空指针,但我不确定。如果 Vec
持有 2 个指针,Rust 是否仍然能够保持相同的内存布局?
Rust 为什么要这样做?对于
Option<u128>
,我们显然可以选择使用 N
字节,与 N > 16
一样长,而 Rust 选择 N = 32
。这当然有很好的特性,例如我们可以仅通过位移位(无乘法)来访问 i
的第 Vec<Option<u128>>
个元素。但如果这是理想的情况,Rust 不应该也将 Option<Vec<T>>
设为 32 字节吗?
Rust 版本:rustc 1.83.0-nightly (1bc403daa 2024-10-11)
Option<Vec<_>>
您已经发现了由
Vec
支持的利基价值优化。更具体地说:
Vec<T>
包含...RawVec<T>
,其中包含...RawVecInner
,其中包含...Unique<u8>
,其中包含...NonZero<*const u8>
.因此,
Option::<Vec<_>>::None
可以表示指针所在位置的 0(这与 NULL *const u8
指针的有效实例不同),以及长度和容量所在位置的任意值。
我不确定你所说的持有两个指针的
Vec
是什么意思。添加一个额外的指针到 Vec
将会使 Vec
和 Option<Vec<_>>
的大小增加指针的大小。
Option<u128>
首先,我们假设
u128
的对齐方式是16
:
println!("{}", std::mem::align_of::<u128>()); // 16
考虑值
vec![Some(0u128), Some(0u128)]
。为了健全性,两个 u128
值必须对齐。按照您的逻辑,Vec
中的第一项必须至少占用 17 个字节(u128
为 16 个字节,enum
判别式为 1)。下一个对齐的内存位置(对齐的倍数)将是从 Vec
开头算起的 32 个字节。由于 Vec
无法在项目之间添加填充,因此填充必须在 Option<u128>
内,使其为 32 字节。