10.3 Enums with Data
A hallmark of Rust enums is that their variants can hold data, combining aspects of both enums and unions in C.
10.3.1 Defining Enums with Data
enum Message { Quit, Move { x: i32, y: i32 }, // Struct-like variant Write(String), // Tuple variant ChangeColor(i32, i32, i32), // Tuple variant }
- Variants:
- Quit: No data.
- Move: Struct-like with named fields.
- Write: A single- Stringin a tuple variant.
- ChangeColor: Three- i32values in a tuple variant.
 
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); }
10.3.3 Comparison with C Unions
In C, you would typically combine a union with a separate tag enum:
#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;
}
- Complexity: You must track which field is valid at any time.
- No Safety: There’s no enforced check to prevent reading the wrong union field.
10.3.4 Advantages of Rust’s Enums with Data
- Type Safety: It’s impossible to read the wrong variant by accident.
- Pattern Matching: Straightforward branching and data extraction.
- Single Type: Functions and collections can deal with multiple variants without extra tagging.