10.3 Enums with Data

Rust's enums can hold data associated with each variant, making them more powerful than C's enums and similar to a combination of C's enums and unions.

10.3.1 Defining Enums with Data

enum Message {
    Quit,
    Move { x: i32, y: i32 },       // Struct variant
    Write(String),                 // Tuple variant
    ChangeColor(i32, i32, i32),    // Tuple variant
}
  • Variants:
    • Quit: No data.
    • Move: A struct variant with named fields x and y.
    • Write: A tuple variant holding a String.
    • ChangeColor: A tuple variant holding three i32 values.

Note: Enums with data can contain any type, including other enums, structs, tuples, or even themselves, allowing for nested and complex data structures.

10.3.2 Creating Instances

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}
fn main() {
let msg1 = Message::Quit;
let msg2 = Message::Move { x: 10, y: 20 };
let msg3 = Message::Write(String::from("Hello"));
let msg4 = Message::ChangeColor(255, 255, 0);
}
  • No Data Variant: Message::Quit requires no additional data.
  • Struct Variant: Message::Move { x: 10, y: 20 } uses named fields.
  • Tuple Variants: Message::Write(String::from("Hello")) and Message::ChangeColor(255, 255, 0) use positional data.

10.3.3 Comparison with C Unions

In C, to achieve similar functionality, you might use a union combined with an enum to track the active type.

#include <stdio.h>
#include <string.h>

enum MessageType {
    Quit,
    Move,
    Write,
    ChangeColor,
};

struct MoveData {
    int x;
    int y;
};

struct WriteData {
    char text[50];
};

struct ChangeColorData {
    int r;
    int g;
    int b;
};

union MessageData {
    struct MoveData move;
    struct WriteData write;
    struct ChangeColorData color;
};

struct Message {
    enum MessageType type;
    union MessageData data;
};

int main() {
    struct Message msg;
    msg.type = Write;
    strcpy(msg.data.write.text, "Hello");

    if (msg.type == Write) {
        printf("Write message: %s\n", msg.data.write.text);
    }
    return 0;
}
  • Manual Management: You need to manually track the active variant using type.
  • No Type Safety: There's potential for errors if the type and data are mismatched.
  • Complexity: Requires more boilerplate code.

10.3.4 Advantages of Rust's Enums with Data

  • Type Safety: Rust ensures that only the valid data for the current variant is accessible.
  • Pattern Matching: Easily destructure and access data in a safe manner.
  • Single Type: The enum is a single type, regardless of the variant, simplifying function signatures and data structures.