rust/src/doc/trpl/enums.md
2015-06-09 16:12:45 -04:00

3.1 KiB
Raw Blame History

% Enums

An enum in Rust is a type that represents data that could be one of several possible variants:

enum Message {
    Quit,
    ChangeColor(i32, i32, i32),
    Move { x: i32, y: i32 },
    Write(String),
}

Each variant can optionally have data associated with it. The syntax for defining variants resembles the syntaxes used to define structs: you can have variants with no data (like unit-like structs), variants with named data, and variants with unnamed data (like tuple structs). Unlike separate struct definitions, however, an enum is a single type. A value of the enum can match any of the variants. For this reason, an enum is sometimes called a sum type: the set of possible values of the enum is the sum of the sets of possible values for each variant.

We use the :: syntax to use the name of each variant: theyre scoped by the name of the enum itself. This allows both of these to work:

# enum Message {
#     Move { x: i32, y: i32 },
# }
let x: Message = Message::Move { x: 3, y: 4 };

enum BoardGameTurn {
    Move { squares: i32 },
    Pass,
}

let y: BoardGameTurn = BoardGameTurn::Move { squares: 1 };

Both variants are named Move, but since theyre scoped to the name of the enum, they can both be used without conflict.

A value of an enum type contains information about which variant it is, in addition to any data associated with that variant. This is sometimes referred to as a tagged union, since the data includes a tag indicating what type it is. The compiler uses this information to enforce that youre accessing the data in the enum safely. For instance, you cant simply try to destructure a value as if it were one of the possible variants:

fn process_color_change(msg: Message) {
    let Message::ChangeColor(r, g, b) = msg; // compile-time error
}

Not supporting these operations may seem rather limiting, but its a limitation which we can overcome. There are two ways: by implementing equality ourselves, or by pattern matching variants with match expressions, which youll learn in the next section. We dont know enough about Rust to implement equality yet, but well find out in the traits section.

Constructors as functions

An enums constructors can also be used like functions. For example:

# enum Message {
# Write(String),
# }
let m = Message::Write("Hello, world".to_string());

Is the same as

# enum Message {
# Write(String),
# }
fn foo(x: String) -> Message {
    Message::Write(x)
}

let x = foo("Hello, world".to_string());

This is not immediately useful to us, but when we get to closures, well talk about passing functions as arguments to other functions. For example, with iterators, we can do this to convert a vector of Strings into a vector of Message::Writes:

# enum Message {
# Write(String),
# }

let v = vec!["Hello".to_string(), "World".to_string()];

let v1: Vec<Message> = v.into_iter().map(Message::Write).collect();