模式的兩種形式: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支持數值和字符的範圍,有如下幾種範圍表達式:
Production | Syntax | Type | Range |
---|---|---|---|
RangeExpr | start..end | std::ops::Range | start ≤ x < end |
RangeFromExpr | start.. | std::ops::RangeFrom | start ≤ x |
RangeToExpr | ..end | std::ops::RangeTo | x < end |
RangeFullExpr | .. | std::ops::RangeFull | - |
RangeInclusiveExpr | start..=end | std::ops::RangeInclusive | start ≤ x ≤ end |
RangeToInclusiveExpr | ..=end | std::ops::RangeToInclusive | x ≤ 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"), _ => (), } }