本文 AI 產出,尚未審核

Rust 課程 – 函數與控制流

主題:條件判斷(ifelse ifelse


簡介

在任何程式語言中,條件判斷都是控制程式執行路徑的核心機制。Rust 以其安全、零成本抽象的設計哲學,提供了與其他語言相似卻更具表達力的 if/else if/else 語法。掌握這些語句不僅能寫出可讀性高的程式,還能在 函式回傳值模式匹配 以及 錯誤處理 等情境中發揮關鍵作用。

本單元將從基本語法講起,逐步深入到 表達式型別推斷範圍檢查 等實務技巧,讓讀者能在日常開發中自信地使用條件判斷,避免常見的陷阱,並遵循最佳實踐。


核心概念

1. if 是表達式,非僅是語句

在 Rust 中,if 本身是一個 表達式(expression),它會產生一個值。這意味著我們可以直接把 if 的結果賦予變數,或作為函式的回傳值。

let number = 7;
let is_even = if number % 2 == 0 { true } else { false };
println!("{} 是偶數嗎? {}", number, is_even);

重點if 的兩個分支({} 內)必須回傳相同型別,否則編譯會失敗。


2. 多重分支:else if

當判斷條件超過兩種情況時,else if 讓程式碼保持平坦結構,避免深層巢狀。

let grade = 85;
let result = if grade >= 90 {
    "優秀"
} else if grade >= 80 {
    "良好"
} else if grade >= 70 {
    "普通"
} else {
    "需加強"
};
println!("成績評等: {}", result);

此範例展示了 連續的比較,每個分支皆回傳相同的 &str 型別。


3. else 的必要性

else 分支是 保底,保證所有可能的情況都有對應的處理。若省略 else,編譯器會要求 if 表達式的結果型別為 ()(單位型別),這在大多數情況下不是我們想要的。

let temperature = -5;
if temperature < 0 {
    println!("結冰了!");
} // 這裡沒有 else,程式仍可編譯,但返回值是 ()

4. if 作為函式回傳值

因為 if 是表達式,我們可以直接在函式中使用它作為回傳值,讓程式更簡潔。

fn max(a: i32, b: i32) -> i32 {
    if a > b { a } else { b }
}

println!("較大的數字是 {}", max(12, 27));

5. 結合 match 前的簡易條件判斷

在某些情況下,if/else if/elsematch 更直觀,特別是 單一變數的範圍檢查

fn categorize(age: u8) -> &'static str {
    if age < 13 {
        "兒童"
    } else if age < 20 {
        "青少年"
    } else if age < 65 {
        "成年人"
    } else {
        "長者"
    }
}

程式碼範例

以下提供 5 個實務上常見的範例,說明不同情境下的條件判斷技巧。

範例 1:使用 if 判斷 Option

fn describe(opt: Option<i32>) -> String {
    // Option<T> 本身不是布林值,必須使用 match 或 if let
    if let Some(value) = opt {
        format!("值為 {}", value)
    } else {
        "沒有值".to_string()
    }
}

說明if let 讓我們只關注 Some 分支,省去完整的 match 寫法。

範例 2:條件運算子(三元運算子)等價寫法

Rust 沒有傳統的三元運算子 condition ? a : b,但可以用 if 表達式達成相同效果。

let speed = 80;
let limit = if speed > 60 { 60 } else { speed };
println!("限速設定為 {} km/h", limit);

範例 3:在迴圈中使用 if 早退

let numbers = vec![1, 4, 6, 9, 12];
for n in numbers {
    if n % 2 == 0 {
        println!("找到第一個偶數: {}", n);
        break; // 早退,類似 `return` 在函式內
    }
}

範例 4:結合 else if 進行錯誤類型分類

enum ErrorKind {
    NotFound,
    PermissionDenied,
    Unexpected,
}

fn handle_error(err: ErrorKind) {
    if let ErrorKind::NotFound = err {
        println!("資源未找到");
    } else if let ErrorKind::PermissionDenied = err {
        println!("權限不足");
    } else {
        println!("未知錯誤");
    }
}

提示:在此情況下 match 更簡潔,但示範 else if 仍有其教學價值。

範例 5:條件編譯(cfg)結合 if

fn platform_message() -> &'static str {
    if cfg!(target_os = "windows") {
        "執行於 Windows"
    } else if cfg!(target_os = "linux") {
        "執行於 Linux"
    } else {
        "執行於其他作業系統"
    }
}
println!("{}", platform_message());

此範例展示了 編譯時條件執行時 if 的結合,用於跨平台程式的訊息顯示。


常見陷阱與最佳實踐

陷阱 說明 改善方式
型別不一致 if/else 兩側回傳不同型別會編譯錯誤。 確保所有分支回傳相同型別,必要時使用 as 轉型或 Box<dyn Trait> 包裝。
忘記 else 省略 else 會使 if 表達式的型別變成 (),導致意外的值傳遞。 若不需要回傳值,使用 if 作為語句;若需要回傳,務必提供 else
過度巢狀 多層 if 會降低可讀性。 考慮改寫為 match、使用 guard 或抽取成小函式。
使用 if letmatch 混淆 if let 只適合單一模式匹配,無法處理多分支。 需要多分支時改用 match;僅需檢查 Some/Ok 時使用 if let
條件表達式過長 直接在 if 中寫長條件會讓程式碼難以閱讀。 把條件抽成布林函式或使用變數命名說明。

最佳實踐

  1. 保持簡潔:每個 if/else if 分支的條件盡量保持單一概念。
  2. 使用 match 替代複雜 if:當分支超過三個或涉及模式解構時,match 更具可讀性。
  3. 避免副作用:盡量不要在條件判斷內執行副作用(如 I/O),以免產生不易預測的行為。
  4. 利用編譯期檢查cfg! 可在條件中直接使用,讓程式在不同平台自動調整。

實際應用場景

  1. 參數驗證
    在函式入口檢查參數合法性,若不符合條件立即回傳錯誤或預設值。

    fn set_volume(level: i32) -> Result<(), &'static str> {
        if !(0..=100).contains(&level) {
            Err("音量必須在 0~100 之間")
        } else {
            // 設定音量的實作
            Ok(())
        }
    }
    
  2. 功能切換(Feature Flag)
    依據環境變數或設定檔啟用/停用特定功能。

    let debug_mode = std::env::var("DEBUG").unwrap_or_default() == "1";
    if debug_mode {
        println!("除錯模式已啟用");
    }
    
  3. 錯誤類型分流
    在網路服務或 CLI 工具中,根據錯誤類別回傳不同的錯誤碼或訊息。

    fn exit_code(err: &str) -> i32 {
        if err.contains("not found") {
            2
        } else if err.contains("permission") {
            3
        } else {
            1
        }
    }
    
  4. 跨平台資源載入
    根據作業系統載入不同的檔案路徑或庫。

    let config_path = if cfg!(target_os = "windows") {
        "C:\\ProgramData\\myapp\\config.toml"
    } else {
        "/etc/myapp/config.toml"
    };
    
  5. 資料分析中的分段統計
    依年齡、收入等欄位將資料分組,計算各組的統計值。

    fn age_group(age: u8) -> &'static str {
        if age < 20 { "青少年" }
        else if age < 40 { "青年" }
        else if age < 60 { "中年" }
        else { "長者" }
    }
    

總結

  • ifelse ifelse 在 Rust 中是表達式,可直接產生值並賦予變數或回傳。
  • 每個分支必須回傳相同型別,否則編譯會失敗。
  • 使用 if let 可以簡化單一模式的匹配;若分支較多,match 更適合
  • 常見陷阱包括型別不一致、忘記 else、過度巢狀等,遵守最佳實踐可提升程式可讀性與安全性。
  • 在實務開發中,條件判斷廣泛應用於 參數驗證、功能切換、錯誤處理、跨平台支援 等情境。

掌握了這些概念與技巧後,你就能在 Rust 程式中靈活運用條件判斷,寫出既安全又易於維護的程式碼。祝你在 Rust 的旅程中玩得開心,寫出更好的程式!