模式的兩種形式:refutable和irrefutable

從前文介紹的幾種模式匹配可知,模式匹配的方式不唯一:

  • (1).模式匹配必須匹配成功,匹配失敗就報錯,主要是變量賦值型的(let/for/函數傳參)模式匹配
  • (2).模式匹配可以匹配失敗,匹配失敗時不執行相關代碼

Rust中為這兩種匹配模式定義了專門的稱呼:

  • 不可反駁的模式(irrefutable):一定會匹配成功,否則編譯錯誤
  • 可反駁的的模式(refutable):可以匹配成功,也可以匹配失敗,匹配失敗的結果是不執行對應分支的代碼

let變量賦值、for迭代、函數傳參這三種模式匹配只接受不可反駁模式。if let和while let只接受可反駁模式。

match則支持兩種模式:

  • 當明確給出分支的Pattern時,必須是可反駁模式,這些模式允許匹配失敗
  • 使用_作為最後一個分支時,是不可反駁模式,它一定會匹配成功
  • 如果只有一個Pattern分支,則可以是不可反駁模式,也可以是可反駁模式

當模式匹配處使用了不接受的模式時,將會編譯錯誤或給出警告。


#![allow(unused)]
fn main() {
// let變量賦值時使用可反駁的模式(允許匹配失敗),編譯失敗
let Some(x) = some_value;

// if let處使用了不可反駁模式,沒有意義(一定會匹配成功),給出警告
if let x = 5 {
  // xxx
}
}

對於match來說,以下幾個示例可說明它的使用方式:


#![allow(unused)]
fn main() {
match value {
  Some(5) => (),  // 允許匹配失敗,是可反駁模式
  Some(50) => (), 
  _ => (),  // 一定會匹配成功,是不可反駁模式
}

match value {
  // 當只有一個Pattern分支時,可以是不可反駁模式
  x => println!("{}", x), 
  _ => (),
}
}

完整的模式語法

下面系統性地介紹Rust中的Pattern語法。

字面量模式

模式部分可以是字面量:


#![allow(unused)]
fn main() {
let x = 1;
match x {
  1 => println!("one"),
  2 => println!("two"),
  _ => println!("anything"),
}
}

模式帶有變量名

例如:

fn main() {
  let x = (11, 22);
  let y = 10;
  match x { 
    (22, y) => println!("Got: (22, {})", y), 
    (11, y) => println!("y = {}", y),    // 匹配成功,輸出22
    _ => println!("Default case, x = {:?}", x), 
  }
  println!("y = {}", y);   // y = 10
}

上面的match會匹配第二個分支,同時為找到的變量y進行賦值,即y=22。這個y只在第二個分支對應的代碼部分有效,跳出作用域後,y恢復為y=10

多選一模式

使用|可組合多個模式,表示邏輯或(or)的意思。


#![allow(unused)]
fn main() {
let x = 1;
match x {
  1 | 2 => println!("one or two"),
  3 => println!("three"), 
  _ => println!("anything"),
}
}

範圍匹配模式

Rust支持數值和字符的範圍,有如下幾種範圍表達式:

ProductionSyntaxTypeRange
RangeExprstart..endstd::ops::Rangestart ≤ x < end
RangeFromExprstart..std::ops::RangeFromstart ≤ x
RangeToExpr..endstd::ops::RangeTox < end
RangeFullExpr..std::ops::RangeFull-
RangeInclusiveExprstart..=endstd::ops::RangeInclusivestart ≤ x ≤ end
RangeToInclusiveExpr..=endstd::ops::RangeToInclusivex ≤ end

但範圍作為模式匹配的Pattern時,只允許使用全閉合的..=範圍語法,其他類型的範圍類型都會報錯。

例如:


#![allow(unused)]
fn main() {
// 數值範圍
let x = 79;
match x {
  0..=59 => println!("不及格"),
  60..=89 => println!("良好"),
  90..=100 => println!("優秀"),
  _ => println!("error"),
}

// 字符範圍
let y = 'c';
match y {
  'a'..='j' => println!("a..j"),
  'k'..='z' => println!("k..z"),
  _ => (),
}
}