Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

enum discriminant

本集目標

了解 enum variant 背後的整數值,以及如何自訂它。

概念說明

每個 variant 都有一個整數值

第 3 章學了 C-style enum。每個 variant 背後都有一個整數,叫做 discriminant。Rust 用它來區分目前是哪個 variant。

enum Color {
    Red,   // 0
    Green, // 1
    Blue,  // 2
}

fn main() {}

預設從 0 開始,每個 variant 遞增 1。

as 取得 discriminant

上一集學了 as。C-style enum 可以用 as 轉成整數看到它的 discriminant:

enum Color {
    Red,   // 0
    Green, // 1
    Blue,  // 2
}

fn main() {
    println!("{}", Color::Red as i32);   // 0
    println!("{}", Color::Green as i32); // 1
    println!("{}", Color::Blue as i32);  // 2
}

自訂 discriminant

手動指定值:

enum HttpStatus {
    Ok = 200,
    NotFound = 404,
    InternalError = 500,
}

fn main() {
    println!("{}", HttpStatus::NotFound as i32); // 404
}

沒指定的 variant 從前一個 +1:

enum Level {
    Low = 1,
    Medium,    // 2
    High,      // 3
    Critical = 10,
    Emergency, // 11
}

#[repr] 控制底層型別

預設的底層型別由編譯器決定。用 #[repr] 明確指定:

#[repr(u8)]
enum Direction {
    North, // 0_u8
    South, // 1_u8
    East,  // 2_u8
    West,  // 3_u8
}

fn main() {}

常見的選擇有 u8u16u32i32 等。

帶資料的 enum 也有 discriminant

帶資料的 enum 內部也有 discriminant 來區分是哪個 variant,但你不能用 as 取得它

enum Shape {
    Circle(f64),
    Rectangle(f64, f64),
}

fn main() {
    Shape::Circle(3.0) as i32; // 編譯錯誤!
}

範例程式碼

#[repr(u8)]
enum Command {
    Quit = 0,
    Move = 1,
    Write = 2,
    ChangeColor = 3,
}

enum Season {
    Spring = 1,
    Summer, // 2
    Autumn, // 3
    Winter, // 4
}

fn main() {
    println!("Quit = {}", Command::Quit as u8);
    println!("Write = {}", Command::Write as u8);

    println!("Spring = {}", Season::Spring as i32);
    println!("Winter = {}", Season::Winter as i32);
}

重點整理

  • 每個 enum variant 都有一個整數 discriminant,預設從 0 遞增
  • C-style enum 可以用 as 轉成整數看到 discriminant
  • 手動指定值用 = 數字,沒指定的從前一個 +1
  • #[repr(u8)] 等控制底層型別
  • 帶資料的 enum 也有 discriminant,但不能用 as 取得