Enums
کلمه کلیدی enum
اجازه ایجاد نوع دادهای را می دهد که دارای چندین گونه مختلف است:
#[derive(Debug)] enum Direction { Left, Right, } #[derive(Debug)] enum PlayerMove { Pass, // Simple variant Run(Direction), // Tuple variant Teleport { x: u32, y: u32 }, // Struct variant } fn main() { let m: PlayerMove = PlayerMove::Run(Direction::Left); println!("On this turn: {:?}", m); }
نکات کلیدی:
- Enumerations allow you to collect a set of values under one type.
Direction
is a type with variants. There are two values ofDirection
:Direction::Left
andDirection::Right
.PlayerMove
is a type with three variants. In addition to the payloads, Rust will store a discriminant so that it knows at runtime which variant is in aPlayerMove
value.- This might be a good time to compare structs and enums:
- In both, you can have a simple version without fields (unit struct) or one with different types of fields (variant payloads).
- You could even implement the different variants of an enum with separate structs but then they wouldn’t be the same type as they would if they were all defined in an enum.
- Rust uses minimal space to store the discriminant.
-
If necessary, it stores an integer of the smallest required size
-
If the allowed variant values do not cover all bit patterns, it will use invalid bit patterns to encode the discriminant (the “niche optimization”). For example,
Option<&u8>
stores either a pointer to an integer orNULL
for theNone
variant. -
شما می توانید در صورت نیاز (به عنوان مثال، برای سازگاری با C) discriminant را کنترل کنید:
#[repr(u32)] enum Bar { A, // 0 B = 10000, C, // 10001 } fn main() { println!("A: {}", Bar::A as u32); println!("B: {}", Bar::B as u32); println!("C: {}", Bar::C as u32); }
بدون
repr
، نوع discriminant دو بایت حافظه اشغال میکند، زیرا 10001 در 2 بایت جا میشود.
-
برای کاوش بیشتر
زبان Rust دارای چندین بهینهسازی دارد که میتواند برای کاهش فضای اشغال شده توسطEnum
ها استفاده کند.
-
Null pointer optimization: For some types, Rust guarantees that
size_of::<T>()
equalssize_of::<Option<T>>()
.کد نمونه, اگر میخواهید نشان دهید که نمایش بیت به بیت در عمل چگونه ممکن است به نظر برسد. مهم است توجه داشته باشید که کامپایلر هیچ تضمینی در مورد این نمایش نمیدهد، بنابراین این کاملاً ناایمن است.
use std::mem::transmute; macro_rules! dbg_bits { ($e:expr, $bit_type:ty) => { println!("- {}: {:#x}", stringify!($e), transmute::<_, $bit_type>($e)); }; } fn main() { unsafe { println!("bool:"); dbg_bits!(false, u8); dbg_bits!(true, u8); println!("Option<bool>:"); dbg_bits!(None::<bool>, u8); dbg_bits!(Some(false), u8); dbg_bits!(Some(true), u8); println!("Option<Option<bool>>:"); dbg_bits!(Some(Some(false)), u8); dbg_bits!(Some(Some(true)), u8); dbg_bits!(Some(None::<bool>), u8); dbg_bits!(None::<Option<bool>>, u8); println!("Option<&i32>:"); dbg_bits!(None::<&i32>, usize); dbg_bits!(Some(&0i32), usize); } }