DEV Community

Cover image for Structs and Enums in Rust
Sonu Bardai
Sonu Bardai

Posted on

Structs and Enums in Rust

Rust is a powerful systems programming language that has been rapidly gaining popularity among developers. One of the reasons for its success is its rich type system, which provides a high level of expressiveness and flexibility when defining custom data types. Two of the most important constructs in Rust’s type system are structures (struct) and enumerations (enum), which allow developers to create complex data types that accurately model the problem domain.

In this blog post, we will take a deep dive into struct and enum in Rust, exploring their syntax, usage, and best practices. We will learn how to use these constructs to create expressive and efficient code that is easy to read, understand, and maintain. Whether you’re new to Rust or an experienced developer looking to deepen your understanding of the language, this post is for you! So grab a cup of coffee and let’s get started on our journey to mastering struct and enum in Rust!

Understanding Structs

Structs are a way to define custom data types in Rust. They allow you to group related data together into a single, cohesive unit. Structs are similar to classes in other languages, but with some important differences.

Let’s say we’re creating a Mario game and we want to represent Mario as a character in our game. We could use a struct to define a Mario type like this:

struct Position {
    x: u32,
    y: u32
}

struct Mario {
    position: Position,
    coins: u32,
    power_up: Option<PowerUp>,
}
Enter fullscreen mode Exit fullscreen mode

In this example, we’ve defined a Mario struct with three fields: position, coins, and power_up. The position field is of type Position, which we defined earlier. The coins field is of type u32, representing the number of coins Mario has collected. The power_up field is of type Option<PowerUp>, representing an optional power-up that Mario may have. We will discuss this type later when we come to Enums.

To create an instance of this struct, we can use the following syntax:

let mario = Mario {
    position: Position { x: 0, y: 0 },
    coins: 0,
    power_up: None,
};
Enter fullscreen mode Exit fullscreen mode

We can access the fields of a struct using dot notation, like this:

let pos = mario.position;
let coins = mario.coins;
let power_up = mario.power_up;
Enter fullscreen mode Exit fullscreen mode

Structs can also have methods, which are functions associated with the struct. Here’s an example of how to define a method for our Mario struct:

impl Mario {
    fn jump(&mut self) {
        self.position.y += 1;
        if let Some(power_up) = self.power_up {
            match power_up {
                PowerUp::SuperMushroom => self.position.y += 1,
                PowerUp::FireFlower => self.position.y += 2,
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example, we’ve defined a method called jump that makes Mario jump. The height of the jump depends on whether Mario has a power-up and what type of power-up it is. To call this method, we can use the following syntax:

mario.jump();
Enter fullscreen mode Exit fullscreen mode

As you can see, structs are a powerful way to define custom data types in Rust. They allow you to group related data together and provide methods for working with that data. In the next section, we’ll explore another important construct in Rust’s type system: enums.

Enum1, Enum2, Enum3

Enums, short for enumerations, are another way to define custom data types in Rust. They allow you to define a type with a fixed set of values, known as variants. Enums are useful when you need to represent a value that can be one of several different options.

Let’s say we want to represent the different power-ups that Mario can have in our game. We could use an enum to define a PowerUp type like this:

enum PowerUp {
    SuperMushroom,
    FireFlower,
    Starman,
    CapeFeather,
}
Enter fullscreen mode Exit fullscreen mode

In this example, we’ve defined an enum called PowerUp with four variants: SuperMushroom, FireFlower, Starman, and CapeFeather. Each variant represents a different type of power-up that Mario can have.

To create an instance of this enum, we can use the following syntax:

let power_up = PowerUp::SuperMushroom;
Enter fullscreen mode Exit fullscreen mode

We can use pattern matching to check which variant an enum value is. Here’s an example of how to do this:

match power_up {
    PowerUp::SuperMushroom => println!("Mario got a Super Mushroom!"),
    PowerUp::FireFlower => println!("Mario got a Fire Flower!"),
    PowerUp::Starman => println!("Mario got a Starman!"),
    PowerUp::CapeFeather => println!("Mario got a Cape Feather!"),
}
Enter fullscreen mode Exit fullscreen mode

In this example, we’re using a match expression to check which variant the power_up value is. Depending on the variant, we print a different message to the screen.

As you can see, enums allow you to represent values that can be one of several different options and provide an expressive way to work with those values. In the next section, we’ll explore how enums and structs can be combined to create even more complex data types.

Combining both our super powers! Structs and Enums

Structs and enums are powerful constructs on their own, but they can be even more powerful when combined. By using enums to group related structs or adding a field to a struct that is an enum type, you can create complex data types that accurately model your problem domain.

Say we want to represent the different enemies that Mario can encounter in our game. We could use an enum to define an Enemy type like this:

enum Enemy {
    Goomba(Goomba),
    KoopaTroopa(KoopaTroopa),
    HammerBro(HammerBro),
}
Enter fullscreen mode Exit fullscreen mode

In this example, we’ve defined an enum called Enemy with three variants: Goomba, KoopaTroopa, and HammerBro. Each variant is associated with a different struct that represents the specific type of enemy.

Here’s what the Goomba struct might look like:

struct Goomba {
    position: Position,
    is_stomped: bool,
}
Enter fullscreen mode Exit fullscreen mode

And here’s what the KoopaTroopa struct might look like:

struct KoopaTroopa {
    position: Position,
    is_stomped: bool,
    is_in_shell: bool,
}
Enter fullscreen mode Exit fullscreen mode

By using an enum to group these related structs together, we can create a single Enemy type that can represent any of the different types of enemies in our game. This makes it easy to write code that can work with any type of enemy, without having to worry about the specific details of each enemy type.

Here’s an example of how we might use this Enemy enum in our code:

fn stomp_enemy(enemy: &mut Enemy) {
    match enemy {
        Enemy::Goomba(goomba) => goomba.is_stomped = true,
        Enemy::KoopaTroopa(koopa) => {
            koopa.is_stomped = true;
            koopa.is_in_shell = true;
        }
        Enemy::HammerBro(_) => {}
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example, we’ve defined a function called stomp_enemy that takes an Enemy as an argument and stomps on it. The behavior of the function depends on which variant of the Enemy enum is passed in. If it’s a Goomba, we set its is_stomped field to true. If it’s a KoopaTroopa, we set both its is_stomped and is_in_shell fields to true. If it’s a HammerBro, we don’t do anything.

Combining structs and enums allows us to create complex data types that accurately model our problem domain. By using enums to group related structs together, we can write code that is expressive, flexible, and easy to understand.

Conclusion

In conclusion, struct and enum are two powerful constructs in Rust's type system that allow developers to define custom data types. Structs are used to group related data together into a single unit, while enums are used to define types with a fixed set of values. By combining structs and enums, developers can create complex data types that accurately model their problem domain.

In this blog post, we've explored the syntax and usage of struct and enum in Rust, providing examples and best practices along the way. We've also seen how these constructs can be combined to create even more powerful data types. Whether you're new to Rust or an experienced developer, we hope this post has deepened your understanding of these important features of the language.

About me

I’m a software engineer and a tech blogger with a passion for writing about the latest developments in the world of technology. I have experience working with a variety of programming languages, including Python, TypeScript, Rust, and Go, and I love sharing my knowledge and insights with others.

When I’m not coding or writing, you can find me exploring the great outdoors, making art. I’m a digital artist who enjoys drawing and painting.

I’m always looking to connect with other tech enthusiasts and artists, so feel free to reach out to me on my socials!

You can find me on:

Twitter: https://twitter.com/SonuBardai

LinkedIn: https://www.linkedin.com/mwlite/in/sonu-bardai

GitHub: https://github.com/SonuBardai

Personal Website: https://sonubardai-portfolio.web.app

Thanks for stopping by, and I hope you enjoyed my blog! Happy coding! 😊

Top comments (0)