枚举类型和Option<枚举类型>的内存表示是什么?

3

还有,我可以使用什么工具来找到这种信息? - puritii
3
我认为你假定了 None 情况必须全部为零。你可以通过一些不安全的内存转换(在此处查看)来使自己清醒。对于 Option<A/B> 的 None,分别编码为 3 和 4。 - kmdreko
@kmdreko 哎呀,这正是我在寻找的。谢谢!也许你可以把它转化为答案,我会标记它的。 - puritii
1个回答

8
免责声明:这里不保证所见到的确切行为始终如此,您不应该依赖具体值。此外,本答案仅基于观察结果,并且仅涉及枚举; 还有关于&T、NonNull、NonZeroU8(以及它们的衍生物)和包含这些东西的嵌套结构的其他内存优化。
基本枚举
如果您有一个简单的非嵌套结构枚举,则默认行为是枚举变量从零开始递增。因此,第一个不可表示的比特模式用作“无”值:
enum Simple { A, B };
println!("{}", unsafe { transmute::<Option<Simple>, u8>(None) });
// prints 2

如果您的简单枚举类型没有嵌套结构,在前面留下了一个间隙,那么`None`值仍将由枚举变量表示之后第一个不可表示的位模式来表示:
enum GapInFront { A = 1, B };
println!("{}", unsafe { transmute::<Option<GapInFront>, u8>(None) });
// prints 3

如果在开头留下空隙,并在比特空间的末尾有一个变量,那么它才会使用全零作为None值。
enum ExtendsToEnd { A = 1, B = 255 };
println!("{}", unsafe { transmute::<Option<ExtendsToEnd>, u8>(None) });
// prints 0

需要注意的一点是,它永远不会在None值的变体之间选择表示形式。即使存在大量不可表示的位模式,占据边界的变体也会导致它使用2字节:

enum Full { A = 0, B = 255 };
println!("{:?}", unsafe { transmute::<Option<Full>, [u8; 2]>(None) });
// prints [0, 60], which I believe is undefined behavior 
// since I think the second byte is left uninitialized

我的猜测是编译器并不跟踪所有可表示的位模式,而仅保留用于执行这些检查的范围。


更有趣的内容。

如果您的枚举类型具有嵌套枚举值的变量,则它也会考虑到该变量:

enum Nested { A, B };
enum Complex { A(Nested), B };
println!("{}", unsafe { transmute::<Option<Complex>, u8>(None) });
// prints 3

然而,如果两个变体具有值,即使它们的位模式不重叠(令人难过),似乎会出现错误。
enum Nested1 { A, B };
enum Nested2 { A=2, B };
enum MoreComplex { A(Nested1), B(Nested2) };
println!("{:?}", unsafe { transmute::<Option<MoreComplex>, [u8; 2]>(None) });
// prints [2, 211], again the second byte is left uninitialized

另外需要指出的是,这并不是Option特有的情况;如果您定义了自己的选项类型,则其行为相同:

enum MyOption<T> { None, Some(T) };
println!("{}", unsafe { transmute::<MyOption<Simple>, u8>(MyOption::None) });
// prints 2

playground上查看此内容。

另请参阅Rust的Option类型的开销是多少?


1
然而,如果两个变量具有值,它似乎会出现错误。这是必须的,因为您必须能够获取对内部值的引用,因此它们必须与相应类型完全表示,并且编译器不能像“Complex :: B”中那样自由选择该值。 - mcarton
@mcarton,你能详细解释一下吗?我认为我已经构建了Nested1Nested2,以便它们可能都可以在单个字节的MoreComplex枚举中表示,而不需要进行修改。 - kmdreko
1
哦,那很可能只是因为没有人费心实现那个优化。看起来你很少有合适的条件去使用它。 - mcarton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接