Rust Enums (Enumeration) Tutorial

In this Rust tutorial we learn how to create enums with custom named constants that represent numerical values, similar to a boolean's true and false.

We cover how to define an enum with types and initialize it with values, as well as how to use an enum with a struct.

Lastly, we take a look at the option generic enum and how it allows us to return values (or null) from an enum.

What is an enum

An enum is a set of named integer constants and allow us to create a set of symbolic names that map to known numerical values. Simply put, an enum is a word that represents a number.

As an example, let’s consider a boolean.

Boolean true and false values are actually just words representing the numbers 1 and 0 respectively. So, when we’re writing true, what we’re really writing is the number 1.

Enums allow us to create our own words that map to numbers like booleans.

An enum is an enumeration, not to be confused with the term enumerator.

How to declare an enum

To declare an enumeration, we write the enum keyword, followed by a unique name and a code block. Inside the code block we declare our actual words that will map to numbers, separated by commas.

Syntax: how to declare an enum
enum EnumName {

    Value1(optional_type),
    Value2(optional_type),
    Value3(optional_type)

}

Enums in Rust are conventionally written with pascal case. In pascal case we write the first letter of the first word in uppercase. Any subsequent words have an uppercase first letter and are not separated with an underscore.

Example: how to declare an enum
// define enum
enum Auth {

    Enabled(i32),
    Disabled(i32)

}

fn main() {}

In the example above, we declare an enum called Auth, with two integer values.

How to initialize an enum with values

To initialize an enum with values, we assign the enum with a value to a variable. We write the enum name, followed by double colon operators and the enum value name. Lastly, we specify a value between parentheses.

Syntax: initialize an enum
  let variable_name = EnumName::ValueName(value);
Example: initialize an enum
#[derive(Debug)]
enum Auth {

    Enabled(i32),
    Disabled(i32)

}

fn main() {

    let yes = Auth::Enabled(1);
    let no = Auth::Disabled(0);

    println!("yes: {:?}", yes);
    println!("no: {:?}", no);

}

In the example above, we assign 1 to Enabled and 0 to Disabled in the variables yes and no.

We cannot print enums like we would normally. Instead we need to implement std::fmt::Debug . The #[derive(Debug)] statement above the enum automatically does that for us.

How to use an enum with a struct

We can assign enum values to struct properties when initializing a struct instance.

Example: using an enum with a struct
#[derive(Debug)]
enum Gender {

    Male,
    Female

}

#[derive(Debug)]
struct Player {
    name: String,
    gender: Gender
}

fn main() {

    // init structs
    let player_1 = Player {
        name: String::from("Gordon Freeman"),
        gender: Gender::Male
    };

    let player_2 = Player {
        name: String::from("Alex Vance"),
        gender: Gender::Female
    };

    println!("Player 1: {:#?}", player_1);
    println!("Player 2: {:#?}", player_2);

}

In the example above, we define our gender property in the Player struct to be able to accept values from the Gender enum. In the initialization of the struct instances we assign the appropriate enum value to the struct property.

Once again we use the #[derive(Debug)] statement above the enum and struct to allow us to print it to the console.

The Option generic enum

The option enum is a predefined generic enum in Rust and allows the enum to return a value. Because of that, the option enum is a generic, which means it has a placeholder for a type.

Option is predefined and only has two values:

  • Some, which returns a value.
  • None, which essentially returns NULL.

Note that Rust doesn’t support the kyeword NULL, so None is used to allow a function to return a null value.

Syntax: Option enum
enum Option<T> {

    Some(T), // returns type of T
    None	 // returns a null value

}

The between the angle brackets is where we specify the type that the Option enum may return. The (T) after Some is where we specify the value that is returned.

Example: Option enum
enum Option<bool> {

    Some(true),
    None

}

Because we specify bool as the generic type, Some can only return true or false. Let’s see it in action.

Example: boolean Option enum
fn main() {

    println!("{:?}", is_even(5));
    println!("{:?}", is_even(88));

}

fn is_even(num:i32) -> Option<bool> {

    if num % 2 == 0 {
        return Some(true);
    } else {
        return None;
    }

}

We’ve taken our is_even function from the functions tutorial and modified it a little bit to return the Option enum.

In this case we only return a boolean true if the number is even, otherwise we return None.

Summary: Points to remember

  • An enum is a set of words that represents a set of numbers similar to a boolean’s true and false.
  • An enum must first be defined with types before it can be initialized with values.
  • The Option enum is a generic enum that returns a value we specify or None.