30 Days of Rust - Day 18

johnnylarner

johnnylarner

Posted on May 14, 2023

30 Days of Rust - Day 18

Hello my dear readers,
Today we're going to fly through enums and have a think about where enums are a better design choice over structs. We'll also take a look at a shorthand match expression known as an if let expression.

Yesterday's questions answered

Today's open questions

  • Nothing open today...

Data and behaviour under one type

In yesterday's post, we saw how structs can be used to group data into fields. Operations on these fields (methods) are then often defined in impl blocks for that struct. We also learned that a struct is also a type. This means that if we want to use functions or methods on different structs declared with very similar fields or methods, we'll need a generic implementation to handle the static typing.

Another alternative is to group these structs as variants of an enum. This is how the Rust std library implements an enum representing different kinds of IP addresses. enums are very flexible in Rust, an enum variant can be of virtually any type. In comparison with Python, enums are central to implementations of key concepts such as Option and Result types.

Matching enums is easy

Part of the reason why enums are baked into the std library and generally useful in Rust design patterns is because of match expressions. enum variants applied in the left side of a match arm often provide for readable and expressive code:

use rand::Rng;
use std::cmp::Ordering;

let my_num = rand::thread_rng().gen_range(1..=100);
let your_num = rand::thread_rng().gen_range(1..=100);

match my_num.cmp(&your_num) {
    Ordering::Less => println!("Your num is bigger than mine."),
    Ordering::Greater => println!("My num is bigger than yours"),
    Ordering::Equal => {
        println!("Our nums are the same...");
        break;
    }
}

Enter fullscreen mode Exit fullscreen mode

Here we use the Ordering enum with the cmp method to handle different cases of a match expression. Well-named enums help developers write clearer code. And as we have already covered, the Rust compiler forces a developer to cover all possible outcomes of an expressions. So you're left with readable and bug-resistant code.

What if your tired of using match

There are cases when you may not want to think about all outcomes of a match expression. The exhaustive nature of a match expression means you may end up repeating boiler plate code to tell the compiler to do nothing. This is more common when you only have 1 condition you care about matching.

The people who develop Rust considered this case and came up with what is known as if let syntax. Let's refactor the above example to demonstrate such a case:

use rand::Rng;
use std::cmp::Ordering;

loop {
    let my_num = rand::thread_rng().gen_range(1..=100);
    let your_num = rand::thread_rng().gen_range(1..=100);

    if let Ordering::Equal = my_num.cmp(&your_num) {
        println!("Our nums are the same...");
        break;
    }
}
Enter fullscreen mode Exit fullscreen mode

If we only care about getting matching numbers, then we can use the if let syntax to move on to the next part of the program. It's worth remembering that the compiler will not help you find all potential outcomes here. So take care when using if let syntax.

💖 💪 🙅 🚩
johnnylarner
johnnylarner

Posted on May 14, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related