feat: added cleanscript
This commit is contained in:
117
ch19/ch19-02-refutability.html
Normal file
117
ch19/ch19-02-refutability.html
Normal file
@@ -0,0 +1,117 @@
|
||||
<!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>
|
||||
Reference in New Issue
Block a user