Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

18.2 可辩驳性:模式是否会无法匹配

18.2.1. 模式的两种形式

模式有两种形式:

  • 可辩驳的(refutable),意味着它们可能匹配失败
  • 无可辩驳的(irrefutable),意味着它们不会失败;你可以把它理解为无论怎么写都会成功的模式

能够匹配任意可能传入值的模式,就是无可辩驳的。例如:

#![allow(unused)]
fn main() {
let x = 5;
}

这个语句不可能失败,因为 x 能匹配表达式右侧所有可能的值。

无法匹配某些可能值的模式,就是可辩驳的。例如:

#![allow(unused)]
fn main() {
if let Some(x) = a_value
}

如果右侧的值是 None,模式就会匹配失败。

函数参数、let 语句和 for 循环只接受无可辩驳模式。例如:

#![allow(unused)]
fn main() {
let a: Option<i32> = Some(5);
let Some(x) = a;
}

Some(x) = a可辩驳的,因为也有可能是 None,但 let 语句只接受无可辩驳模式,所以编译器会报错。那该怎么改呢?可以使用 if let,也可以使用 let...else 来处理匹配失败的情况:

#![allow(unused)]
fn main() {
let a: Option<i32> = Some(5);
if let Some(x) = a {
    // ...
}
}
#![allow(unused)]
fn main() {
let a: Option<i32> = Some(5);
let Some(x) = a else {
    return;
};
}

if letwhile letlet...else 同时支持可辩驳无可辩驳模式。实际上,如果你在 if letwhile letlet...else 中使用无可辩驳模式,编译器会发出警告,因为从概念上讲这里本来就存在失败的可能。例如:

#![allow(unused)]
fn main() {
if let x = 5 {
    println!("{x}");
};
}

输出:

$ cargo run
   Compiling patterns v0.1.0 (/tmp/ch18-refresh/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.09s
     Running `target/debug/patterns`
5

编译器会警告 “irrefutable if let pattern”。那是因为:在本应用于可辩驳模式的上下文中使用无可辩驳模式,是没有意义的。

基于这些概念,再想想 match 表达式的分支:除了最后一个分支以外,其他分支都应该是可辩驳的;而最后一个分支应该是无可辩驳的,因为它需要匹配所有剩余情况。