Welcome to this comprehensive guide on Exhaustive Matching in Rust! In this lesson, we'll delve into the world of pattern matching and learn how to ensure all possible values are accounted for. By the end of this tutorial, you'll have a solid understanding of this essential Rust concept. Let's get started! š
Pattern matching is a powerful feature in Rust that allows us to deconstruct data structures like tuples, structs, and enums. It's a great way to extract specific values from complex data structures, check for conditions, and handle different cases.
Exhaustive matching ensures that we have covered all possible cases for a given enum variant. In other words, it helps us make sure that every possible value for an enum variant is accounted for in our pattern matches.
enum TrafficLight {
Red,
Yellow,
Green,
}
fn main() {
let traffic_light = TrafficLight::Red;
match traffic_light {
TrafficLight::Red => println!("Stop!"),
TrafficLight::Yellow => println!("Prepare to stop!"),
TrafficLight::Green => println!("Go!"),
}
}In the example above, we have an enum TrafficLight with three variants: Red, Yellow, and Green. We also have a main function that creates a TrafficLight with the value Red and uses pattern matching to print out a message corresponding to the value.
š Note: The order of the pattern matches in the match block is important. The matching starts from the top and stops at the first matching case.
What happens if we forget to include a case in our match block for an existing enum variant? Let's find out!
fn main() {
let traffic_light = TrafficLight::Green;
match traffic_light {
TrafficLight::Red => println!("Stop!"),
TrafficLight::Yellow => println!("Prepare to stop!"),
// Missing Green case
}
}When we run the above code, Rust will give us a helpful error message telling us that we have forgotten to handle the TrafficLight::Green case:
error[E0006]: missing matches in enum `TrafficLight`
--> src/main.rs:8:5
|
7 | match traffic_light {
| - help: ensure all arms in this `match` are reachable (see `--explain E0006`)
8 | TrafficLight::Red => println!("Stop!");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9 | TrafficLight::Yellow => println!("Prepare to stop!");
| ^^^^^^^^^^^^^^^^^^^
10 | }
| - help: ensure all variants of `TrafficLight` are covered by the match arms (see `--explain E0006`)
This error message is a great reminder to ensure we've covered all our bases in the pattern matching!
Sometimes, we might not care about the specific value for a given case. In such cases, we can use the wildcard pattern _ to match any value:
fn main() {
let traffic_light = TrafficLight::Green;
match traffic_light {
TrafficLight::Red => println!("Stop!"),
TrafficLight::Yellow => println!("Prepare to stop!"),
_ => println!("Continue with caution."), // Matches all remaining cases
}
}Let's consider a more complex example with a Result enum that represents the success or failure of an operation:
enum Result {
Ok(i32),
Err(String),
}
fn main() {
let result = Result::Ok(42);
match result {
Result::Ok(value) => println!("The result is successful: {}", value),
Result::Err(error_message) => println!("An error occurred: {}", error_message),
}
}What is Exhaustive Matching in Rust?
That's it for our Exhaustive Matching tutorial! Now you have a good understanding of pattern matching and how to ensure that all possible values are accounted for in your Rust programs. Happy coding! š