列舉
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); }
This slide should take about 5 minutes.
重點:
- Enumerations allow you to collect a set of values under one type.
Direction
是含變體的型別,有Direction::Left
和Direction::Right
這兩個值。PlayerMove
是含三種變體的型別。除了酬載之外,Rust 還會儲存判別值,以便在執行階段瞭解哪個變體屬於PlayerMove
值。- 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 會以最少的空間來儲存判別值。
-
如有需要,Rust 會儲存最小所需大小的整數
-
如果允許的變體值未涵蓋所有位元模式,Rust 會使用無效的位元模式來編碼判別值 (即「區位最佳化」)。舉例來說,
Option<&u8>
可儲存指向整數的指標,也可儲存None
變體適用的NULL
。 -
您可以視需要控制判別值,例如為了與 C 相容:
#[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
,判別值型別會需要 2 個位元組,因為 10001 適合 2 個位元組。
-
探索更多內容
Rust 支援多種最佳化做法,可用於縮減列舉占用的空間。
-
空值指標最佳化:針對部分型別,Rust 保證
size_of::<T>()
等於size_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); } }