Rust Enum

Enums (or enumerations) is a user-defined data type that allows us to select a value from a list of related values.

In Rust, we use the enum keyword to create an enum. For example,

enum Sport {
    Basketball,
    Volleyball,
    Football,
    Cricket,
}

Here, we have created an enum named Sport with a list of values Basketball, Volleyball, Football and Cricket. These enum values are known as variants.


When to use Enum in Rust

Let's look at a situation where we want to define an enum.

Suppose you are creating a program where you have to store a list of directions, and we know that there will be only four possible values for directions: North, East, West, and South.

In this case, we can use an enum where each variant will be the direction.

enum Direction {
    North,
    East,
    South,
    West,
}

Now we can access each of the enum variants whenever we have to use a direction in our program.

Note: By convention, we use the Pascal case for enum names and values. In Pascal case, we write the first letter of the word(s) in uppercase.


Accessing Enum Variants in Rust

To access enum values, we first have to create enum instances. For example,

enum Direction {
    North,
    East
    South,
    West,
}

Now let's create instances of each enum variant:

let north = Direction::North;
let east = Direction::East;
let south = Direction::South;
let west = Direction::West;

Here, Direction::North represents the enum variant North of the Direction enum, and we are assigning it to the variable north.

Similarly, Direction::East, Direction::South and Direction::West represent variants East, South, and West.


Rust Enum Data Type

Now let's see one example of how enum works in Rust.

fn main() {

    // define enum Direction
    #[derive(Debug)]
    enum Direction {
        North,
        East,
        South,
        West,
    }

    // initialize and access enum variants
    let north = Direction::North;
    let east = Direction::East;
    let south = Direction::South;
    let west = Direction::West;

    // print enum values
    println!("{:?}", north);
    println!("{:?}", east);
    println!("{:?}", south);
    println!("{:?}", west);
}

Output

North
East
South
West

Here, we have created enum instances:

  • north - to access enum variant Direction::North
  • east - to access enum variant Direction::East
  • south - to access enum variant Direction::South
  • west - to access enum variant Direction::West

We have then printed these instances.

Note: We have used #[derive(Debug)] above the enum definition. It's because this allows Rust to print the variants inside the enum.


Example: Enum Data Type in Rust

Let's see one more example.

fn main() {

    // define enum color
    #[derive(Debug)]
    enum Color {
        Green,
        Yellow,
        Red,
    }

    // initialize and access enum variants
    let green = Color::Green;
    let yellow = Color::Yellow;
    let red = Color::Red;

    // print enum values
    println!("{:?}", green);
    println!("{:?}", yellow);
    println!("{:?}", red);
}

Output

Green
Yellow
Red

Initializing Enum Variants with Values in Rust

In Rust, we can also initialize enum variants by assigning individual values. For example,

fn main() {
    // define enum
    #[derive(Debug)]
    enum Result {
        Score(f64),
        Valid(bool),
    }

// initialize enum with values let num = Result::Score(3.14); let bool = Result::Valid(true);
println!("num = {:?}", num); println!("bool = {:?}", bool); }

Output

num = Score(3.14)
bool = Valid(true)

In the above example, we have created an enum named Result with two variants: Score (f64 type) and Valid (boolean type).

Notice the statements to create enum instances.

let num = Result::Score(3.14);
let bool = Result::Valid(true);

Here, we are initializing the enum variants with values inside the bracket. That is,

  • Result::Score(3.14) - initialize the Score variant with the value 3.14
  • Result::Valid(true) - initialize the Valid variant with the value true

Enum with different Data Types in Rust

In Rust, we can also create enums where the enum variants are of different data types: struct, tuple, string, etc.

1. Enum with a struct variant

enum Game {
    Quit,
    Position { x: i32, y: i32 },
}

Here the Game enum has an anonymous struct Position { x: i32, y: i32 } as a variant.

2. Enum with a tuple variant

enum Game {
    Quit,
    ChangeBackground(i32, i32, i32),
}

Here, the Game enum has a tuple ChangeBackground(i32, i32, i32) as a variant.

3. Enum with a string variant

enum Game {
    Quit,
    Print(String),
}

Here, the Game enum has a Print(String) variant.


Example: Enum Variants of Different Data Types

Earlier, we see that enum variants can be of different data types. We can even create an enum where each variant is of a different type. That is one variant will be a string, another one will be a struct and so on. For example,

enum Game {
    Quit,
    Print(String),
    Position { x: i32, y: i32 },
    ChangeBackground(i32, i32, i32),
}

This enum has four different types of variants:

  • Quit has no data associated with it at all
  • Print includes a single String
  • Position includes an anonymous struct inside it
  • ChangeBackground includes three i32 values (tuple)

Let's look at an example of how we can use this enum,

fn main() {
    // define enum with multiple variants and data types
    #[derive(Debug)]
    enum Game {
        Quit,
        Print(String),
        Position { x: i32, y: i32 },
        ChangeBackground(i32, i32, i32),
    }

// initialize enum with values let quit = Game::Quit; let print = Game::Print(String::from("Hello World!")); let position = Game::Position { x: 10, y: 20 }; let color = Game::ChangeBackground(200, 255, 255);
// print enum values println!("quit = {:?}", quit); println!("print = {:?}", print); println!("position = {:?}", position); println!("color = {:?}", color); }

Here, we initialize the enum with values according to the enum definition.

Let's look at the Position variant from the Game enum,

enum Game {
    ..
    Position { x: i32, y: i32 }
    ..
}

Now, to assign a value, we target the variant Position and initialize it with values in the same format as the enum definition.

let position = Game::Position { x: 10, y: 20 };

Here, we initialize the struct variant Position with x: 10 and y: 20.

Similarly, we have assigned values to all the other variants and printed it on the screen.

let quit = Game::Quit;
let print = Game::Print(String::from("Hello World!"));
let color = Game::ChangeBackground(200, 255, 255);

Mutable Enum in Rust

To create a mutable enum, we can use the mut keyword while initializing the enum.

Suppose we have an enum,

// enum definition
enum Animal {
    Dog(String, f64),
    Cat(String, f64),
}

// create mutable enum variant
let mut dog = Animal::Dog("Tucker", 37.4);

Example: Mutable Enum

fn main() {
    // define enum with multiple variants and data types
    #[derive(Debug)]
    enum Animal {
        Dog(String, f64),
        Cat(String, f64),
    }

// initialize a mutable enum variant with values let mut dog = Animal::Dog(String::from("Tucker"), 37.4);
// initialize a non-mutable enum variant with values let cat = Animal::Cat(String::from("Maya"), 22.3); // print enum values before change println!("dog before = {:?}", dog); println!("cat before = {:?}", cat);
// change the value of mutable enum variant dog = Animal::Dog(String::from("Sterling"), 21.1);
// print enum values after change println!(); println!("dog after = {:?}", dog); println!("cat after = {:?}", cat); }

Output

dog before = Dog("Tucker", 37.4)
cat before = Cat("Maya", 22.3)

dog after = Dog("Sterling", 21.1)
cat after = Cat("Maya", 22.3)

Here, we have initialized an enum variant and assigned it to a variable dog using the mut keyword.

let mut dog = Animal::Dog(String::from("Tucker"), 37.4);

This allows us to change the value of the dog variable. In the program above, we change the dog variable to,

dog = Animal::Dog(String::from("Sterling"), 21.1);

As a result, the value of the variable dog changes from Dog("Tucker", 37.4) to Dog("Sterling", 21.1).