Enumerations
In the previous chapter we looked at the Option
type. If we examine the definition of Option
we see that it is
actually an enumeration:
#![allow(unused)] fn main() { pub enum Option<T> { None, Some(T), } }
An enumeration is a type that can have a fixed set of values. In the case of Option
, the values are None
and Some(T)
.
Unlike in other languages, Rust's enumerations can hold data. In the case of Option
, the Some
variant holds a value
of type T
. T
is a generic type parameter, which means that Option
can hold any type of value.
Let's look at another example of an enumeration:
#![allow(unused)] fn main() { enum Direction { Up, Down, Left, Right, } }
In this example, Direction
is an enumeration with four variants: Up
, Down
, Left
, and Right
. Each variant
represents a direction.
Imagine we would like to include the velocity of the movement in the Direction
enumeration. We can do this by
associating data with each variant:
#![allow(unused)] fn main() { enum Direction { Up(u32), Down(u32), Left(u32), Right(u32), } }
The power of enumerations becomes apparent when we use them in combination with match
expressions. A match
expression allows us to match on the different variants of an enumeration and execute different code based on the
variant.
Let's look at an example:
fn main() { move_player(Direction::Up(10)); } enum Direction { Up(u32), Down(u32), Left(u32), Right(u32), } fn move_player(direction: Direction) { match direction { Direction::Up(velocity) => println!("Moving up with velocity: {velocity}"), Direction::Down(velocity) => println!("Moving down with velocity: {velocity}"), Direction::Left(velocity) => println!("Moving left with velocity: {velocity}"), Direction::Right(velocity) => println!("Moving right with velocity: {velocity}"), } }
The associated data in the enumeration variants can be different for each variant. For an elevator, we might want to
treat the vertical movement differently from the horizontal movement. We can do this by associating different data
with the Up
and Down
variants.
fn main() { move_elevator(Direction::Up(10)); } enum Direction { Up(u32), Down(u32), Left, Right, } fn move_elevator(direction: Direction) { match direction { Direction::Up(velocity) | Direction::Down(velocity) => println!("Moving up or down with velocity: {velocity}"), Direction::Left | Direction::Right => println!("Call 911!"), } }
C-style Enumerations
Rust also has C-style enumerations, which are similar to enumerations in C. They are defined using the enum
keyword
without any associated data:
#[repr(u8)] enum Color { Red = 0, Green = 1, Blue = 2, } fn main() { println!("Red: {}", Color::Blue as u8); }
This is a less-commonly used feature in Rust, but it can be useful when you need to map values to integers.