Optional Results
Explore how to use Rust's Option enum to manage optional data safely and idiomatically. Understand handling exhaustive pattern matching for enums, and practice implementing functions that return optional results without errors.
We'll cover the following...
The Loch Ness monster lives in Scotland. Dracula lives in Transylvania. But no one knows where Bigfoot or aliens live. Let’s write some code for this:
This won’t compile. We haven’t handled the cases of bigfoot or aliens. The compiler tells us this:
error[E0004]: non-exhaustive patterns: `&Bigfoot` and `&Alien` not covered
--> src/main.rs:20:15
|
2 | / enum Monster {
3 | | LochNess,
4 | | Dracula,
5 | | Bigfoot,
| | ------- not covered
6 | | Alien,
| | ----- not covered
7 | | }
| |_- `Monster` defined here
...
20 | match self {
| ^^^^ patterns `&Bigfoot` and `&Alien` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
We need to give some response for those other monsters. One possibility would be to add an Unknown variant to Place:
But this doesn’t feel quite right. Unknown isn’t a place like Scotland. We’re mixing up two different concepts. Instead, the Rust way to handle this would be with an extra wrapper enum type, like this:
Cool, that works. Now let’s talk about the food our monsters eat. Dracula eats blood, and aliens eat cows (I guess). But we don’t know about the other two monsters. We can write up two new enums to help:
But our OptionalFood and OptionalPlace look really similar! It would be nice if there was some way to unify them into a single type. Thinking back to type parameters, we can try using a type parameter and creating an Optional enum:
In fact, this kind of thing is so common in Rust, that the std crate and its prelude provide an enum for this purpose out of the box. It’s called Option, and it has two variants: Some (like our Known) and None (like our Unknown). Rewriting our lives method to use it makes our code more idiomatic (or normal) Rust:
NOTE: Astute readers may be asking, why did we get to say
Someinstead ofOption::Some? There’s nouse Option::*;statement! The answer is thatOption,Some, andNoneare such common parts of Rust programming that thepreludeautomatically adds theusefor all three of them.
Exercise
Implement the eats method so that the program below succeeds. Don’t modify the main function.