30 Days of Rust - Day 18
Tags: rust, learning, beginners
Published: 2023-05-14 15:21:09

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
- Rust will auto deref [as much as is required](https://stackoverflow.com/questions/36426207/why-does-rust-not-deref-string-to-str?noredirect=1&lq=1#comment60472747_36426207). It will add a maximum of one reference to the result.

## 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:
```rust
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;
	}
}

```

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:
```rust
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;
	}
}
```

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.