From 057691cbc71014aaf1c53d61fd5e271495176a39 Mon Sep 17 00:00:00 2001 From: Zheng Ping Date: Mon, 19 Jun 2017 23:05:46 +0800 Subject: [PATCH] Create ch18-02-refutability.md --- src/ch18-02-refutability.md | 100 ++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/ch18-02-refutability.md diff --git a/src/ch18-02-refutability.md b/src/ch18-02-refutability.md new file mode 100644 index 0000000..f71b776 --- /dev/null +++ b/src/ch18-02-refutability.md @@ -0,0 +1,100 @@ +## Refutability: Whether a Pattern Might Fail to Match + +Patterns come in two forms: refutable and irrefutable. Patterns which cannot +fail to match for any possible value are said to be *irrefutable*, and patterns +which can fail to match for some possible value are said to be *refutable*. +`let` statements, function parameters, and `for` loops are restricted to only +accept irrefutable patterns, since there's nothing correct the program could do +if the pattern fails to match. `if let`, and `while let` expressions are +restricted to only accept refutable patterns, since they're made to handle +possible failure and we wouldn't need their functionality if the pattern could +never fail. + +In general, you shouldn't have to worry about the distinction between refutable +and irrefutable patterns; just be familiar with the concept of refutability +when you see it mentioned in an error message. When you get an error message +involving refutability, you'll need to change either the pattern or the +construct you're using the pattern with, depending on your intentions for the +behavior of the code. + +Let's look at some examples. Earlier in this chapter, we had `let x = 5;`. `x` +is indeed an irrefutable pattern we're allowed to use: since it matches +anything, it can't fail to match. In contrast, consider trying to match one +variant of an enum with `let`, such as matching only a `Some` value from the +`Option` enum as shown in Listing 18-7: + +```rust,ignore +let Some(x) = some_option_value; +``` + +Listing 18-7: Attempting to use a refutable pattern with +`let` + +If `some_option_value` was a `None` value, `some_option_value` would not match +the pattern `Some(x)`. The pattern `Some(x)` is refutable since there exists a +case in which it would fail to match a value. There's nothing valid that our +code could do with this `let` statement if `some_option_value` was the `None` +value. Therefore, Rust will complain at compile time that we've tried to use a +refutable pattern where an irrefutable pattern is required: + +```text +error[E0005]: refutable pattern in local binding: `None` not covered + --> :3:5 + | +3 | let Some(x) = some_option_value; + | ^^^^^^^ pattern `None` not covered +``` + +We didn't cover (and couldn't cover!) every valid value with the pattern +`Some(x)`, so Rust will rightfully complain. + +If we have a refutable pattern, instead of using `let`, we can use `if let`. +That way, if the pattern doesn't match, the code inside the curly braces won't +execute. That code will only make sense and run if the value matches the +pattern. Listing 18-8 shows how to fix the code in Listing 18-7 with `Some(x)` +matching `some_option_value`. Using the refutable pattern `Some(x)` is allowed, +since this example uses `if let`: + +```rust +# let some_option_value: Option = None; +if let Some(x) = some_option_value { + println!("{}", x); +} +``` + +Listing 18-8: Using `if let` and a block with refutable +patterns instead of `let` + +Consequently, if we give `if let` an irrefutable pattern that will always match, +such as `x` as shown in Listing 18-9: + +```rust,ignore +if let x = 5 { + println!("{}", x); +}; +``` + +Listing 18-9: Attempting to use an irrefutable pattern +with `if let` + +Rust will complain that it doesn't make sense to use `if let` with an +irrefutable pattern: + +```text +error[E0162]: irrefutable if-let pattern + --> :2:8 + | +2 | if let x = 5 { + | ^ irrefutable pattern +``` + +Generally, match arms use refutable patterns, except for the last arm that +might match any remaining values with an irrefutable pattern. A `match` with +only one arm whose pattern is irrefutable is allowed, but it's not particularly +useful and could be replaced with a simpler `let` statement. Both the expressions +associated with a `let` statement and a single arm irrefutable match will +unconditionally be run, so the end result is the same if their expressions are. + +Now that we've discussed all the places that patterns can be used and the +difference between refutable and irrefutable patterns, let's go over all the +syntax we can use to create patterns.