Getting started with Rust: Enum on steroids!
Tags: rust
Published: 2018-04-01 16:06:28

---
title: Getting started with Rust: Enum on steroids!
published: true
description: Let just cover quickly the basics of enum in rust
tags: Rust
---
*Originally posted on my [blog](https://www.mathieu-nivoliez.com/posts/2018-04-01-getting-started-with-rust-enum-on-steroids.html)*

Hello everyone! Today subject was hard to decide on. But as the previous one was pretty tedious, I decided to go a subject more easy to speak of. So, today we are going to talk about enum in Rust!

## "Yeah,.... but what is an enum anyway?"
Let me explain this first. An enum (or enumeration) is a type where all possible value are listed.
To give an example, let say that I can take care of different dogs: doggo, doge and pupper.

Then we can define a enum to represent that:
```rust
enum DogKind {
  Doggo,
  Doge,
  Pupper
}
```
Let's decompose that. First we use the keyword `enum` to express that we are going to define an enum. Then there is the name of the enum, in our case it is *DogKind*. Then, between `{ ... }` we define all possible value of *DogKind* separate with comas.

We are now able to use it as this:
```rust
fn take_care_of_dog(kind: DogKind) {
  match kind {
    DogKind::Doggo => take_care_of_doggo(),
    DogKind::Doge => take_care_of_doge(),
    DogKind::Pupper => take_care_of_pupper(),
  }
}
```
Do you remember in the previous posts when I said that it is a good practice to read out loud the code? Enum in Rust are a good practice for that. Let do it for training.
We declare a function `fn` called `take_care_of_dog` which take a parameter `kind` of type `DogKind`. We know that `DogKind` is an enum define before. Then we check if which value of `DogKind` the parameter `kind` matches. And for every possible match, we define an action to follow. Here the arrow can be read as *then, do that*, so the match statement can be read as *if it match Doggo, then do that*.

## "Ok, I have use other language before, this is just a switch case, no?"
Fair enough. But it is only the begining. Let me show you something really fun.

Let take again our example from before, upgraded a bit:
```rust
enum DogKind {
  Doggo(String),
  Doge(String, String, String),
  Pupper { age: f32 }
}
```
## "What the f... ... Freacking duck?"
That usually the response if you have never used language with tagged union.
Let me explain, for each *value* of *DogKind*, we want to have specific values, specific properties.
You can use this like that:
```rust
fn say_something_about_dog(kind: DogKind) {
  match kind {
    DogKind::Doggo(name) => println!("Good boy, {}", name),
    DogKind::Doge(such, wow, much) => println!("Such {}, wow {}, much {}", such, wow, much),
    DogKind::Pupper { age } => println!("Oh this pupper is {} years old", age)
  }
}
```
## "Wow, such variant... But are we oblidge to express all possible case into the match statement?"
The match is exhaustive, meaning that you have to describe *ALL* cases.
Well, there is a syntaxic element that allow you describe the "default case": the `_` placeholder.
```rust
fn say_something_about_dog(kind: DogKind) {
  match kind {
    DogKind::Doggo(name) => println!("Good boy, {}", name),
    DogKind::Doge(such, wow, much) => println!("Such {}, wow {}, much {}", such, wow, much),
    DogKind::Pupper { age } => println!("Oh this pupper is {} years old", age),
    _ => println!("What is that? it's not a dog... Is it alive?"),
  }
}
```
But, I cannot stress you enough that the default case is not robust. For example, let say that you add a kind of dogs: the *Doggy*. Then no match statement with the `_` will fail to compile because this new kind will fall into the default case.
Again, the `_` is not *evil*, it is a powerful too that must be use carefully.

## "What about doing the same thing for different value?"
We can do that easily with the `|`:

```rust
enum DogKind {
  Doggo,
  Doggy,
  Doge,
  Pupper
}

fn great_dog(kind: DogKind) {
  match kind {
    Doggo | Doggy => println!("Who is a good boy? It's you!"),
    Doge => println!("Wow, such elagance, much raffinment"),
    Pupper => println!("How adorable!"),
  }
}
```
## "Ok, are they other things we have to know about enum and match expression?"
Yeah. First you can use brackets inside match expression:

```rust
enum DogKind {
  Doggo,
  Doggy,
  Doge,
  Pupper
}

fn great_dog(kind: DogKind) {
  match kind {
    Doggo | Doggy => println!("Who is a good boy? It's you!"),
    Doge => println!("Wow, such elagance, much raffinment"),
    Pupper => {
      println!("How adorable!");
      println!("I pet the pupper");
    },
  }
}
```
And you can use match expression as assignment.
## "Wait... what?"
Yep! Let say that you got a value that depends of the type of dog, you could write something like:

```rust
enum DogKind {
  Doggo,
  Doggy,
  Doge,
  Pupper
}

fn great_dog(kind: DogKind) {
  let action = match kind {
    Doggo | Doggy | Pupper => "Pet the dog",
    Doge => "Pay your respect to the venerable doge"
  }; // note the ";" at the end of the assignment expression.
  println!("{}", action); 
}
```
## "Ok, seems useful..."
Yeah it is, and you want to know something? You probably already use it.
The `Result<T,E>` and `Option<T>` are enum themself.
And they are a good example of enum with traits...

But we will see traits the next time :p

So, see you next time for more, do not hesitate to comment any error, suggestion or anything about this post.

-- Mathieu