RSS

Getting Started with Rust – Enums

Enums in Rust Banner

Enums in Rust have some properties over and above those found in C/C++

  • Data can be associated with them
  • Methods can be implemented for an enum

The final item in the list was only briefly covered in chapter 6 of The Rust Programming Language book so we will expand on this here.

Simple Enums

As with C/C++, simple enums are symbolic representations of a concept or value. You don’t necessarily need to know what the value is, you can simply use the symbolic name.

enum Message {
    MoveByOffset,
    MoveTo
}

The above code could represent an operation in a game to move a sprite/character etc. This is very much like C/C++, it becomes more interesting when we associate data to an enum.

Enums Can be Associated with Data

Enums can also have data associated with them. So the above enum could be embellished to have the offset and coordinate data associated with the move operations:

enum Message {
    MoveByOffset { x: i32, y: i32 },
    MoveTo { x: i32, y: i32 }
}

Another feature of enums is that not all of the symbolic names (variants) need to have the same data type associated with them. The Message enum could be expanded to encompass more operations:

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

Here we have messages with different data associated with them and even one without any data. We can even have methods implemented for an enum:

impl Message {
    fn call(&self) {
        // method body would be defined here
    }
}

let m = Message::Write(String::from("hello"));
m.call();

Here, we have a call method that can be executed for a Message enum.

Differentiating Between Enums

So far everything looks pretty much like the code in chapter 6 of the Rust book.

The thing that is not covered at this point is how to access the data in the different messages and just as importantly, determine the exact variant of the enum that has been instantiated. For this we need the match statement along with the self parameter in the call method. This is best illustrated by an example:

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

impl Message {
    fn call(&self) {
        match self {
            Message::Quit => println!("Quit message received"),
            Message::Move { x, y } => println!("Move to coordinates: ({}, {})", x, y),
            Message::Write(text) => println!("Write message: {}", text),
            Message::ChangeColor(r, g, b) => { println!("Change color to RGB({}, {}, {})", r, g, b) }
        }
    }
}

fn main() {
    let m1 = Message::Write(String::from("Hello"));
    m1.call();

    let m2 = Message::Move { x: 10, y: 20 };
    m2.call();

    let m3 = Message::ChangeColor(255, 0, 0);
    m3.call();

    let m4 = Message::Quit;
    m4.call();
}

Running this application results in the following output:

Write message: Hello
Move to coordinates: (10, 20)
Change color to RGB(255, 0, 0)
Quit message received

Here, self is used to determine which variant of the Message is calling the method call and match ensures that the appropriate action is taken.

Conclusion

The above application is a trivial illustration of using match to work with enums with different variants but it was not covered very well in the text. A little investigation was required.

Next Up

Project Structure.

Tags: ,

Tuesday, November 4th, 2025 at 9:46 am • Rust, Software DevelopmentRSS 2.0 feed • leave a response or trackback

Leave a Reply

*