Match 是什么語法?PHP8 也加了
大家好,我是站長 polarisxu。
這是 Rust 勸退系列的第 8 個教程,探討 Rust 中的模式匹配。
01 match 表達式
關于 match 表達式,很多其他語言并沒有,比如 Go 語言。不過有些語言開始支持 match,比如 PHP 8.0 就有了 match 表達式。
一般地可以認為 match 和 switch 類似,所以 Rust 中沒有 switch。
match 用于檢查某個當前的值是否匹配一組/列值中的某一個。看一個具體的例子:
- fn test_match(number: i32) -> &'static str {
- match number {
- // 匹配單個值
- 1 => {println!("One!"); "One!"},
- // 匹配多個值
- 2 | 3 | 5 | 7 | 11 => "This is a prime",
- // 匹配一個閉區間范圍
- 13..=19 => "A teen",
- // 處理其他情況
- _ => "Ain't special",
- }
- }
看起來是一個簡單的語法結構,但大概率在其他語言沒見過。簡單解釋下:
- 跟其他語言的 switch 類似,可以匹配多個分支;多個分支之間,使用 , 分隔;
- 在 match 分支中,=> 左側是模式,因此叫做模式匹配,比如 | 表示匹配多個值;..= 表示匹配一個范圍;右側是在左側匹配成功時要執行的操作;
- match 要求窮盡,也就是要包含所有可能的值。因此提供了 _,用來處理所有其他情況,類似 switch 的 default 分支;但只要窮盡了,可以沒有 _;
- 如果右側操作是多個語句,需要放在 {} 中;
- match 是表達式,它的結果是匹配到的模式中,執行操作的最后一個表達式的結果。這在 Rust 中是很常見的,之前提到過,Rust 中一切皆表達式。所以,這個例子中 match 表達式的值即為函數的返回值。因此,match 的所有分支必須返回同一數據類型;
- 注意 match 表達式最后是否有分號的區別;
日常吐槽:在 match 中匹配區間,如果想和 for in 一樣,使用 .. 來表示半閉半開區間,結果報錯。看到資料說應該使用 …,但卻提示該語法已廢棄!為啥語法結構還不保持一致呢?!
看一個接收 match 結果的例子:
- let boolean = true;
- let binary = match boolean {
- false => 0,
- true => 1,
- }; // 注意這里的分號
- println!("{} -> {}", boolean, binary);
02 match 其他用法
上面介紹了常規的 match 操作。match 還有很多其他的用法。
解構
當元組和 match 一起時,可以解構元組。
- fn main() {
- // 試一試將不同的值賦給 `pair`
- let pair = (0, -2);
- println!("Tell me about {:?}", pair);
- // match 可以解構一個元組
- match pair {
- // 解構出第二個值
- (0, y) => println!("First is `0` and `y` is `{:?}`", y),
- (x, 0) => println!("`x` is `{:?}` and last is `0`", x),
- _ => println!("It doesn't matter what they are"),
- // `_` 表示不將值綁定到變量
- }
- }
關于枚舉和指針、引用和 match 的結合,以后遇到再講解。
guard 語句
在 match 分支中可以加上過濾條件。接著上面元組解構的例子:
- fn main() {
- let pair = (2, -2);
- println!("Tell me about {:?}", pair);
- match pair {
- (x, y) if x == y => println!("These are twins"),
- // `if` 條件部分是一個衛語句
- (x, y) if x + y == 0 => println!("Antimatter, kaboom!"),
- (x, _) if x % 2 == 1 => println!("The first one is odd"),
- _ => println!("No correlation..."),
- }
- }
綁定
這是什么意思呢?看一個例子:(來自 rust by example)
- // `age` 函數,返回一個 `u32` 值。
- fn age() -> u32 {
- 15
- }
- fn main() {
- println!("Tell me type of person you are");
- match age() {
- 0 => println!("I'm not born yet I guess"),
- // 可以直接 `match` 1 ..= 12,但怎么把歲數打印出來呢?
- // 在 1 ..= 12 分支中綁定匹配值到 `n` 。現在年齡就可以讀取了。
- n @ 1 ..= 12 => println!("I'm a child of age {:?}", n),
- n @ 13 ..= 19 => println!("I'm a teen of age {:?}", n),
- // 不符合上面的范圍。返回結果。
- n => println!("I'm an old person of age {:?}", n),
- }
- }
match 后是一個函數,我們希望在分支中,根據匹配結果,使用 age 函數的返回值。當然,這個例子有點多此一舉,完全可以在 match 之前用變量存儲 age 函數的返回值。
那換一個例子:
- fn some_number() -> Option<u32> {
- Some(41)
- }
- fn main() {
- match some_number() {
- Some(n @ 40..=42) => println!("The Answer: {}!", n),
- Some(n) => println!("Not interesting... {}", n),
- _ => (),
- }
- }
- 關于 Option 以后講解
這個例子很好的講解了綁定的作用:分支中想要使用匹配的結果,通過 @ 符號可以將匹配的結果和某個變量綁定,然后就可以使用這個變量了。
03 if let 和 while let
這兩個結構其他語言沒見過,可以理解為是某些場景下替代 match,讓代碼更簡潔,因為 match 必須窮盡所有情況,而 if let 和 while let 沒有此限制。
以下代碼:
- let some_u8_value = Some(3u8);
- match some_u8_value {
- Some(3) => println!("three"),
- _ => (), // 有點多余
- }
改為 if let:
- let some_u8_value = Some(3u8);
- if let Some(3) = some_u8_value {
- println!("three");
- }
和 match 一樣,if let 和 while let 都是表達式;
- if/while let 等號左側是模式,右側是要匹配的值;所以當右側的值和左側的模式匹配時,執行對應的語句塊;所以,有時候 if let 也可以單純的當做解構使用;
- if let 支持普通的 else if 和 else;while let 沒有 else;
- while let 語法和 if let 類似。這里就不舉例子了。
04 小結
Rust 中的 match 雖然和其他語言的 switch 類似,很顯然,match 的復雜度比 switch 高。當然,不管復雜與否,最關鍵還是要實際使用,需要不斷實際練習。
通常,match 和 Option、枚舉一起使用,因此,在講解這兩個知識點時,一般會使用到 match。
本文轉載自微信公眾號「polarisxu」,可以通過以下二維碼關注。轉載本文請聯系polarisxu公眾號。