if let 簡單控制流

ch06-03-if-let.md
commit a86c1d315789b3ca13b20d50ad5005c62bdd9e37

if let 語法讓我們以一種不那麼冗長的方式結合 iflet,來處理只匹配一個模式的值而忽略其他模式的情況。考慮範例 6-6 中的程序,它匹配一個 Option<u8> 值並只希望當值為 3 時執行程式碼:


#![allow(unused)]
fn main() {
let some_u8_value = Some(0u8);
match some_u8_value {
    Some(3) => println!("three"),
    _ => (),
}
}

範例 6-6:match 只關心當值為 Some(3) 時執行程式碼

我們想要對 Some(3) 匹配進行操作但是不想處理任何其他 Some<u8> 值或 None 值。為了滿足 match 表達式(窮盡性)的要求,必須在處理完這唯一的成員後加上 _ => (),這樣也要增加很多樣板代碼。

不過我們可以使用 if let 這種更短的方式編寫。如下代碼與範例 6-6 中的 match 行為一致:


#![allow(unused)]
fn main() {
let some_u8_value = Some(0u8);
if let Some(3) = some_u8_value {
    println!("three");
}
}

if let 獲取通過等號分隔的一個模式和一個表達式。它的工作方式與 match 相同,這裡的表達式對應 match 而模式則對應第一個分支。

使用 if let 意味著編寫更少代碼,更少的縮進和更少的樣板代碼。然而,這樣會失去 match 強制要求的窮盡性檢查。matchif let 之間的選擇依賴特定的環境以及增加簡潔度和失去窮盡性檢查的權衡取捨。

換句話說,可以認為 if letmatch 的一個語法糖,它當值匹配某一模式時執行程式碼而忽略所有其他值。

可以在 if let 中包含一個 elseelse 塊中的代碼與 match 表達式中的 _ 分支塊中的代碼相同,這樣的 match 表達式就等同於 if letelse。回憶一下範例 6-4 中 Coin 枚舉的定義,其 Quarter 成員也包含一個 UsState 值。如果想要計數所有不是 25 美分的硬幣的同時也報告 25 美分硬幣所屬的州,可以使用這樣一個 match 表達式:


#![allow(unused)]
fn main() {
#[derive(Debug)]
enum UsState {
   Alabama,
   Alaska,
}

enum Coin {
   Penny,
   Nickel,
   Dime,
   Quarter(UsState),
}
let coin = Coin::Penny;
let mut count = 0;
match coin {
    Coin::Quarter(state) => println!("State quarter from {:?}!", state),
    _ => count += 1,
}
}

或者可以使用這樣的 if letelse 表達式:


#![allow(unused)]
fn main() {
#[derive(Debug)]
enum UsState {
   Alabama,
   Alaska,
}

enum Coin {
   Penny,
   Nickel,
   Dime,
   Quarter(UsState),
}
let coin = Coin::Penny;
let mut count = 0;
if let Coin::Quarter(state) = coin {
    println!("State quarter from {:?}!", state);
} else {
    count += 1;
}
}

如果你的程序遇到一個使用 match 表達起來過於囉嗦的邏輯,記住 if let 也在你的 Rust 工具箱中。

總結

現在我們涉及到了如何使用枚舉來創建有一系列可列舉值的自訂類型。我們也展示了標準庫的 Option<T> 類型是如何幫助你利用類型系統來避免出錯的。當枚舉值包含數據時,你可以根據需要處理多少情況來選擇使用 matchif let 來獲取並使用這些值。

你的 Rust 程序現在能夠使用結構體和枚舉在自己的作用域內表現其內容了。在你的 API 中使用自訂類型保證了類型安全:編譯器會確保你的函數只會得到它期望的類型的值。

為了向你的用戶提供一個組織良好的 API,它使用起來很直觀並且只向用戶暴露他們確實需要的部分,那麼現在就讓我們轉向 Rust 的模組系統吧。