Learning Rust #1: Pattern Matching
Tags: rust, learning
Published: 2021-03-11 09:38:40

---
title: Learning Rust #1: Pattern Matching
published: true
description: Last December I finally started learning Rust and last month I built and published my first app with Rust: 235. Learning Rust is my new monthly blog series that is definitely not a tutorial but rather a place for me to keep track of my learning and write about things I've learned along the way.
tags: rust, learning
series: Learning Rust
canonical_url: https://hamatti.org/posts/learning-rust-pattern-matching/
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y6f2ecy1s4usfv148q0h.png
---

_Last December I finally started learning Rust and last month I built and published my first app with Rust: [235](https://hamatti.org/posts/introducing-235/). Learning Rust is my new monthly blog series that is definitely not a tutorial but rather a place for me to keep track of my learning and write about things I've learned along the way._

_My process of learning is reading some guides and docs (with Rust, I started with [The Rust Book](https://doc.rust-lang.org/book/) and [Rust by Example](https://doc.rust-lang.org/rust-by-example/index.html)), then I try to make something that works, ask a lot of questions from the community, improve, fix bugs, read some more and now I'm writing blog posts which require me to do more research and help me futher improve my program._

The first concept that I've really liked and that I have not used in other languages is the [`match`](https://doc.rust-lang.org/book/ch06-02-match.html) operator for pattern matching. In correct use cases, it can make the code nice and easy to read but it also can end up becoming a messy spaghetti. I'm currently still trying to figure out when it's best to use and when not.

## Basics of pattern matching

First use case I have for match is to map team name abbreviations from the API into the city names I want to use in the app:

```rust
let str_form = match abbr {
        "BOS" => "Boston",
        "BUF" => "Buffalo",
        "NJD" => "New Jersey",
        "NYI" => "NY Islanders",
        "NYR" => "NY Rangers",
        "PHI" => "Philadelphia",
        "PIT" => "Pittsburgh",
        "WSH" => "Washington",
        "CAR" => "Carolina",
        "CHI" => "Chicago",
        "CBJ" => "Columbus",
        "DAL" => "Dallas",
        "DET" => "Detroit",
        "FLA" => "Florida",
        "NSH" => "Nashville",
        "TBL" => "Tampa Bay",
        "ANA" => "Anaheim",
        "ARI" => "Arizona",
        "COL" => "Colorado",
        "LAK" => "Los Angeles",
        "MIN" => "Minnesota",
        "SJS" => "San Jose",
        "STL" => "St. Louis",
        "VGK" => "Vegas",
        "CGY" => "Calgary",
        "EDM" => "Edmonton",
        "MTL" => "Montreal",
        "OTT" => "Ottawa",
        "TOR" => "Toronto",
        "VAN" => "Vancouver",
        "WPG" => "Winnipeg",
        _ => "[unknown]",
    };
```

_(Editor's note: while writing this blog post, I'm exposing myself to how bad my variable naming is in this project. That's partially because so much mental energy is spent on figuring out how to write Rust that there's not much left for thinking about good names. I'll fix 'em little by little as I refactor so it might be that at the moment you're reading this, I have already renamed them in [the source](https://github.com/Hamatti/nhl-235)._

Another example of how I use `match` in 235 is when deciding how to print lines of goals:

```rust
let score_iter = home_scores.into_iter().zip_longest(away_scores.into_iter());

for pair in score_iter {
  match pair {
    Both(l, r) => print_full(l, r),
    Left(l) => print_left(l),
    Right(r) => print_right(r),
  }
}
```

Here, I have `score_iter` (again, not the greatest name, I admit) which is a Zip that supports uneven lengths. For example, it could look something like this (this example is pseudo, the actual data is more complex. `_` denotes a missing value):

```
[
  ((Appleton, 2), (Boeser, 0)),
  (_, (Hoglander, 8)),
  (_, (MacEwen, 26)),
  (_, (Boeser, 57))
]
```

By matching these pairs, each line will either be (`itertools::EitherOrBoth::`)`Both` which means both values are there, `Left` meaning only the left value exists and `Right` for only right value existing. Matching these with `match pair`, it's nice and clean to run the corresponding print function.

![Text lined up in three columns with second column having 3 more rows than first and third](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xs3n2ltf20vsx5apsz8z.png)

This second `match` example also showcases binding where we bind the values into variables `l` and `r` so we can refer to them inside the expressions.

## Options and Results

Another very handy use case for `match` is with `Result` and `Option`. My main logic when running 235 on the command line is done within `api()` function that returns `Result<(), reqwest::Error>`.

```rust
match api() {
  Ok(_) => (),
  Err(err) => println!("{:?}", err),
};
```

Since `Result` will either be `Ok` or `Err`, I'm matching `Ok` with no-op and `Err` with printing out the error into the console.

Example with doing similar with `Option` is

```rust
games.into_iter().for_each(|game| match game {
  Some(game) => print_game(&game),
  None => (),
})
```

Here, if a game was parsed correctly, it will be `Some` and if it didn't, it will be `None` so we can just skip the `None` case and only print the games that were parsed correctly from the data.

## Guards

One thing I haven't used yet and only learned about it while doing research for this blog post is [guards](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html#extra-conditionals-with-match-guards). They are essentially additional if clauses combined with a pattern so you can differentiate similar values based on extra condition.

The example in [Rust by Example](https://doc.rust-lang.org/rust-by-example/flow_control/match/guard.html) is this:

```rust
let pair = (2, -2);

match pair {
  (x, y) if x == y => println!("These are twins"),
  (x, y) if x + y == 0 => println!("Antimatter, kaboom!"),
  (x, _) if x % 2 == 1 => println!("The first one is odd"),
  _ => println!("No correlation..."),
}
```

I haven't yet run into cases where I'd have use for the guards but wanted to record it here so you'll know it exists.

## Conclusion

All in all, `match` might be my favorite syntactic thing in Rust so far. Sometimes it feels bit too much like a hammer (in sense of if all you have is a hammer, every problem starts to look like a nail) in that I tend to overuse it even when other means would make more sense. But I'm sure it's something that I'll find the right balance as I code more with Rust.