Using Match – Bob Revisited
Tags: rust, beginners
Published: 2019-08-06 01:08:59

---
title: Using Match – Bob Revisited
published: true
tags: Rust, beginners
canonical_url: https://rust.graystorm.com/2019/07/17/using-match-bob-revisited/
cover_image: https://rust.graystorm.com/wp-content/uploads/2019/06/plant-wood-old-rust-equipment-gear-1278587-pxhere.com_.jpg
---

![TRY AGAIN in Scrabble letter - as I try again with an Exercism task, this time using match.](https://i2.wp.com/rust.graystorm.com/wp-content/uploads/2019/07/board-games-encouragement-games-scrabble-spell-spelling-1520271-pxhere.com_.jpg?fit=840%2C461&ssl=1)<figcaption>Wait, “TG”? That's not a word! Challenge!</figcaption>

Remember Bob from a [previous post](https://rust.graystorm.com/2019/07/01/return-to-string-basics/) – our tiniest of AI-responders? I got feedback from the [Exercism](https://exercism.io/) tutor that I had avoided one of `Rust`'s most versatile of operators and I should think about using match. So, not to be a jerk, but just to see if I could replace ALL of the `if`s in my method, I quickly came up with this solution.

## Switch to Using Match

```
pub fn reply(message: &str) -> &str {
    let message = message.trim();
    let question = message.ends_with('?');
    let any_alpha = message.chars().any(char::is_alphabetic);
    let is_yelling = message.to_ascii_uppercase() == message;
    let is_empty = message.len() == 0;
    match message.is_empty() {
        true => "Fine. Be that way!",
        _ => match any_alpha && is_yelling {
            true => match question {
                true => "Calm down, I know what I'm doing!",
                _ => "Whoa, chill out!",
            },
            _ => match !is_empty && question {
                true => "Sure.",
                _ => "Whatever.",
            },
        },
    }
}
```

## Come On Bob, Get With the Rust

So, it may be my newness to Rust, but I’m not sure version 2 is “more maintainable” code than what I started with. I had thought this Exercism task was just about learning some string methods. Turns out, it is also about learning the `match` operator. Of course, you wouldn’t code any parser or AI this way anyway – this IS just for practice.

Another tiny thing the tutor pointed out, I did have `let check_message = message.trim()` in my earlier code. A more idiomatic way in Rust is to reassign it to the same variable, hence the `let message = message.trim()` in this version. My guess is: less memory allocation, fewer variables for you to keep track of, and you aren’t able to incorrectly use the wrong variable later in the method. Actually, that probably isn’t a Rust idea – that’s just a good programming tip.

## Bob With a Trait

Patterns are, I'm told, very powerful in Rust and that's a big reason to start using `match` wherever you can. I’ve also learned a bit about `traits` and `impls` which I talked about in an [earlier post](https://rust.graystorm.com/2019/07/10/rust-functions-methods-and-traits/). And that got me thinking maybe I’d work through the syntax to get it working with a `trait` instead. That idea led to this code.

```
pub fn reply(message: &str) -> &str {
    enum Quality {
        Empty,
        YellQuestion,
        YellStatement,
        AskQuestion,
        Statement, };

    trait HasQuality {
        fn has_quality(&self) -> Quality;
    }

    impl HasQuality for str {
        fn has_quality(&self) -> Quality {
            let message = self.trim();
            let question = message.ends_with('?');
            let any_alpha = message.chars().any(char::is_alphabetic);
            let is_yelling = message.to_ascii_uppercase() == message;
            let is_empty = message.len() == 0;

            match message.is_empty() {
                true => Quality::Empty,
                _ => match any_alpha && is_yelling {
                    true => match question {
                        true => Quality::YellQuestion,
                        _ => Quality::YellStatement,
                    },
                    _ => match !is_empty && question {
                        true => Quality::AskQuestion,
                        _ => Quality::Statement,
                    },
                },
            }
        }
    };
    match message.has_quality() {
        Quality::Empty => "Fine. Be that way!",
        Quality::YellQuestion => "Calm down, I know what I'm doing!",
        Quality::YellStatement => "Whoa, chill out!",
        Quality::AskQuestion => "Sure.",
        _ => "Whatever.",
    }
}
```

So here, we come up with the idea of a Quality `trait` and then we implement that `trait` for the built-in `str` primitive. We’ve expanded what you can do to a `str` with our own `trait`! Version 3 of Bob really helps reveal some of the Rust thought patterns I need to hone.

Of course, I made sure Version 3 still passes all of the Exercism tests for this task. This change was approaching my limit of Rust knowledge to get it working without help from a book – just obeying every compiler complaint. However, I cranked this out much faster than previous Rust code, so I think some of this learning (and blogging) is sinking in! I surprised myself enough, that I [posted this solution to Exercism](https://exercism.io/tracks/rust/exercises/bob/solutions/ea9b6aab73c249e5b7710d5c705da7c7) as well. I want to hear what the tutor has to say about this method (no pun intended!). Now, I just need to remember to keep using match, traits, impls, and other Rust-supplied power!

## Update: 2019-07-17 13:30

Woah, I just got some great advice from the Exercism tutor! You can `match` on a `(expression, expression, ...)` so check this out!

```
impl HasQuality for str {
    fn has_quality(&self) -> Quality {
        let message = self.trim();
        let question = message.ends_with('?');
        let any_alpha = message.chars().any(char::is\_alphabetic);
        let is_yelling = message.to_ascii_uppercase() == message;
        let is_empty = message.len() == 0;

        match (is_empty, any_alpha && is_yelling, question) {
            (true, _, _) => Quality::Empty,
            (false, true, true) => Quality::YellQuestion,
            (false, true, false) => Quality::YellStatement,
            (false, false, true) => Quality::AskQuestion,
            _ => Quality::Statement,
        }
    }
};
```

The post [Using Match – Bob Revisited](https://rust.graystorm.com/2019/07/17/using-match-bob-revisited/) appeared first on [Learning Rust](https://rust.graystorm.com).