可反驳性:模式是否可能无法匹配
模式有两种形式:可反驳和不可反驳。与传递的任何可能值匹配的模式是无可辩驳的。一个例子是语句 let x = 5
中的 x
;因为 x
匹配任何内容,因此不会失败
进行匹配。可能无法匹配某些可能值的模式包括
可反驳。例如,如果 let Some(x) = a_value
,则表达式中的 Some(x)
是因为如果 a_value
变量中的值为 None
而不是
某些,
则 Some(x)
模式将不匹配。
函数参数、let
语句和 for
循环只能接受无可辩驳的模式,因为当值不匹配时,程序无法执行任何有意义的作。if let
和 while let
表达式接受可反驳和不可反驳的模式,但编译器会警告不可反驳的模式,因为根据定义,它们旨在处理可能的失败:条件的功能在于它能够根据成功或失败执行不同的作。
一般来说,你不必担心 rereftable 和 unrerefable 模式之间的区别;但是,您确实需要熟悉可反驳性的概念,以便在错误消息中看到它时可以做出响应。在这些情况下,您需要更改模式或您正在使用该模式的构造,具体取决于代码的预期行为。
让我们看一个例子,当我们尝试使用可反驳模式时会发生什么
其中 Rust 需要一个无可辩驳的模式,反之亦然。示例 18-8 显示了一个
let
语句,但对于该模式,我们指定了 Some(x),
一个可反驳的模式。如您所料,此代码将无法编译。
fn main() {
let some_option_value: Option<i32> = None;
let Some(x) = some_option_value;
}
示例 18-8:尝试使用
让
如果 some_option_value
是 None
值,则它将无法匹配模式
Some(x)
来解释,这意味着该模式是可反驳的。但是,let
语句只能接受无可辩驳的模式,因为代码无法对 None
值执行任何有效作。在编译时,Rust 会抱怨我们试图在需要无可辩驳的模式的地方使用可反驳的模式:
$ 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/ch18-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
因为我们没有用 Some(x)
模式覆盖(也无法覆盖)每个有效值,所以 Rust 理所当然地产生了编译器错误。
如果我们有一个可反驳的模式,需要一个不可反驳的模式,我们可以通过更改使用该模式的代码来修复它:我们可以使用 if let
,而不是使用 let
。然后,如果模式不匹配,代码将跳过大括号中的代码,从而为其提供一种有效继续的方法。示例 18-9 展示了如何修复示例 18-8 中的代码。
fn main() { let some_option_value: Option<i32> = None; if let Some(x) = some_option_value { println!("{x}"); } }
示例 18-9:使用 if let
和具有可反驳模式的块而不是 let
我们已经给代码一个输出了!此代码现在完全有效。但是,如果我们给 if let
一个无可辩驳的模式(一个永远匹配的模式),比如 x
,如示例 18-10 所示,编译器会给出警告。
fn main() { if let x = 5 { println!("{x}"); }; }
示例 18-10:尝试使用 if let
的无可辩驳的模式
Rust 抱怨说,将 if let
与无可辩驳的模式一起使用没有意义:
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
warning: irrefutable `if let` pattern
--> src/main.rs:2:8
|
2 | if let x = 5 {
| ^^^^^^^^^
|
= note: this pattern will always match, so the `if let` is useless
= help: consider replacing the `if let` with a `let`
= 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`
5
因此,match arm 必须使用可反驳的模式,但最后一个 arm 除外,它应该使用不可反驳的模式匹配任何剩余的值。Rust 允许我们在只有一个手臂的比赛中
使用无可辩驳的模式,但是
此语法不是特别有用,可以用更简单的
let
语句。
现在你知道在哪里使用模式以及可反驳模式和不可反驳模式之间的区别,让我们介绍一下我们可以用来创建模式的所有语法。