Enum Sizes
Rust enums are packed tightly, taking constraints due to alignment into account:
use std::mem::{align_of, size_of}; macro_rules! dbg_size { ($t:ty) => { println!("{}: size {} bytes, align: {} bytes", stringify!($t), size_of::<$t>(), align_of::<$t>()); }; } enum Foo { A, B, } #[repr(u32)] enum Bar { A, // 0 B = 10000, C, // 10001 } fn main() { dbg_size!(Foo); dbg_size!(Bar); dbg_size!(bool); dbg_size!(Option<bool>); dbg_size!(&i32); dbg_size!(Option<&i32>); }
- See the Rust Reference.
Key Points:
- Internally Rust is using a field (discriminant) to keep track of the enum variant.
Bar
enum demonstrates that there is a way to control the discriminant value and type. Ifrepr
is removed, the discriminant type takes 2 bytes, becuase 10001 fits 2 bytes.- As a niche optimization an enum discriminant is merged with the pointer so that
Option<&Foo>
is the same size as&Foo
. Option<bool>
is another example of tight packing.- For some types, Rust guarantees that
size_of::<T>()
equalssize_of::<Option<T>>()
. - Zero-sized types allow for efficient implementation of
HashSet
usingHashMap
with()
as the value.