Files
docs-rust/ch19/ch19-02-refutability.html
2026-06-22 21:27:36 +05:30

118 lines
6.9 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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 dont 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, theyre
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 shouldnt 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, youll need to change either the pattern or the construct youre
using the pattern with, depending on the intended behavior of the code.</p>
<p>Lets 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, weve 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&lt;i32&gt; = 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 weve 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
--&gt; 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&lt;i32&gt;`
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 didnt cover (and couldnt 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 doesnt 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&lt;i32&gt; = 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>Weve 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 doesnt 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
--&gt; 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 isnt 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, lets cover all the syntax we can use to create
patterns.</p>
</body>
</html>