118 lines
6.9 KiB
HTML
118 lines
6.9 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Refutability: Whether a Pattern Might Fail to Match</title>
|
||
</head>
|
||
<body>
|
||
<h2 id="refutability-whether-a-pattern-might-fail-to-match"><a class="header" href="#refutability-whether-a-pattern-might-fail-to-match">Refutability: Whether a Pattern Might Fail to Match</a></h2>
|
||
<p>Patterns come in two forms: refutable and irrefutable. Patterns that will match
|
||
for any possible value passed are <em>irrefutable</em>. An example would be <code>x</code> in the
|
||
statement <code>let x = 5;</code> because <code>x</code> matches anything and therefore cannot fail
|
||
to match. Patterns that can fail to match for some possible value are
|
||
<em>refutable</em>. An example would be <code>Some(x)</code> in the expression <code>if let Some(x) = a_value</code> because if the value in the <code>a_value</code> variable is <code>None</code> rather than
|
||
<code>Some</code>, the <code>Some(x)</code> pattern will not match.</p>
|
||
<p>Function parameters, <code>let</code> statements, and <code>for</code> loops can only accept
|
||
irrefutable patterns because the program cannot do anything meaningful when
|
||
values don’t match. The <code>if let</code> and <code>while let</code> expressions and the
|
||
<code>let...else</code> statement accept refutable and irrefutable patterns, but the
|
||
compiler warns against irrefutable patterns because, by definition, they’re
|
||
intended to handle possible failure: The functionality of a conditional is in
|
||
its ability to perform differently depending on success or failure.</p>
|
||
<p>In general, you shouldn’t have to worry about the distinction between refutable
|
||
and irrefutable patterns; however, you do need to be familiar with the concept
|
||
of refutability so that you can respond when you see it in an error message. In
|
||
those cases, you’ll need to change either the pattern or the construct you’re
|
||
using the pattern with, depending on the intended behavior of the code.</p>
|
||
<p>Let’s look at an example of what happens when we try to use a refutable pattern
|
||
where Rust requires an irrefutable pattern and vice versa. Listing 19-8 shows a
|
||
<code>let</code> statement, but for the pattern, we’ve specified <code>Some(x)</code>, a refutable
|
||
pattern. As you might expect, this code will not compile.</p>
|
||
<figure class="listing" id="listing-19-8">
|
||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">fn main() {
|
||
</span><span class="boring"> let some_option_value: Option<i32> = None;
|
||
</span> let Some(x) = some_option_value;
|
||
<span class="boring">}</span></code></pre>
|
||
<figcaption><a href="#listing-19-8">Listing 19-8</a>: Attempting to use a refutable pattern with <code>let</code></figcaption>
|
||
</figure>
|
||
<p>If <code>some_option_value</code> were a <code>None</code> value, it would fail to match the pattern
|
||
<code>Some(x)</code>, meaning the pattern is refutable. However, the <code>let</code> statement can
|
||
only accept an irrefutable pattern because there is nothing valid the code can
|
||
do with a <code>None</code> value. At compile time, Rust will complain that we’ve tried to
|
||
use a refutable pattern where an irrefutable pattern is required:</p>
|
||
<pre><code class="language-console">$ cargo run
|
||
Compiling patterns v0.1.0 (file:///projects/patterns)
|
||
error[E0005]: refutable pattern in local binding
|
||
--> src/main.rs:3:9
|
||
|
|
||
3 | let Some(x) = some_option_value;
|
||
| ^^^^^^^ pattern `None` not covered
|
||
|
|
||
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
|
||
= note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html
|
||
= note: the matched value is of type `Option<i32>`
|
||
help: you might want to use `let else` to handle the variant that isn't matched
|
||
|
|
||
3 | let Some(x) = some_option_value else { todo!() };
|
||
| ++++++++++++++++
|
||
|
||
For more information about this error, try `rustc --explain E0005`.
|
||
error: could not compile `patterns` (bin "patterns") due to 1 previous error
|
||
</code></pre>
|
||
<p>Because we didn’t cover (and couldn’t cover!) every valid value with the
|
||
pattern <code>Some(x)</code>, Rust rightfully produces a compiler error.</p>
|
||
<p>If we have a refutable pattern where an irrefutable pattern is needed, we can
|
||
fix it by changing the code that uses the pattern: Instead of using <code>let</code>, we
|
||
can use <code>let...else</code>. Then, if the pattern doesn’t match, the code in the curly
|
||
brackets will handle the value. Listing 19-9 shows how to fix the code in
|
||
Listing 19-8.</p>
|
||
<figure class="listing" id="listing-19-9">
|
||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
||
</span><span class="boring"> let some_option_value: Option<i32> = None;
|
||
</span> let Some(x) = some_option_value else {
|
||
return;
|
||
};
|
||
<span class="boring">}</span></code></pre>
|
||
<figcaption><a href="#listing-19-9">Listing 19-9</a>: Using <code>let...else</code> and a block with refutable patterns instead of <code>let</code></figcaption>
|
||
</figure>
|
||
<p>We’ve given the code an out! This code is perfectly valid, although it means we
|
||
cannot use an irrefutable pattern without receiving a warning. If we give
|
||
<code>let...else</code> a pattern that will always match, such as <code>x</code>, as shown in Listing
|
||
19-10, the compiler will give a warning.</p>
|
||
<figure class="listing" id="listing-19-10">
|
||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
||
</span> let x = 5 else {
|
||
return;
|
||
};
|
||
<span class="boring">}</span></code></pre>
|
||
<figcaption><a href="#listing-19-10">Listing 19-10</a>: Attempting to use an irrefutable pattern with <code>let...else</code></figcaption>
|
||
</figure>
|
||
<p>Rust complains that it doesn’t make sense to use <code>let...else</code> with an
|
||
irrefutable pattern:</p>
|
||
<pre><code class="language-console">$ cargo run
|
||
Compiling patterns v0.1.0 (file:///projects/patterns)
|
||
warning: irrefutable `let...else` pattern
|
||
--> src/main.rs:2:5
|
||
|
|
||
2 | let x = 5 else {
|
||
| ^^^^^^^^^
|
||
|
|
||
= note: this pattern will always match, so the `else` clause is useless
|
||
= help: consider removing the `else` clause
|
||
= note: `#[warn(irrefutable_let_patterns)]` on by default
|
||
|
||
warning: `patterns` (bin "patterns") generated 1 warning
|
||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.39s
|
||
Running `target/debug/patterns`
|
||
</code></pre>
|
||
<p>For this reason, match arms must use refutable patterns, except for the last
|
||
arm, which should match any remaining values with an irrefutable pattern. Rust
|
||
allows us to use an irrefutable pattern in a <code>match</code> with only one arm, but
|
||
this syntax isn’t particularly useful and could be replaced with a simpler
|
||
<code>let</code> statement.</p>
|
||
<p>Now that you know where to use patterns and the difference between refutable
|
||
and irrefutable patterns, let’s cover all the syntax we can use to create
|
||
patterns.</p>
|
||
</body>
|
||
</html>
|