Rust 課程 – 函數與控制流
主題:條件判斷(if、else if、else)
簡介
在任何程式語言中,條件判斷都是控制程式執行路徑的核心機制。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/else 比 match 更直觀,特別是 單一變數的範圍檢查。
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 let 與 match 混淆 |
if let 只適合單一模式匹配,無法處理多分支。 |
需要多分支時改用 match;僅需檢查 Some/Ok 時使用 if let。 |
| 條件表達式過長 | 直接在 if 中寫長條件會讓程式碼難以閱讀。 |
把條件抽成布林函式或使用變數命名說明。 |
最佳實踐:
- 保持簡潔:每個
if/else if分支的條件盡量保持單一概念。 - 使用
match替代複雜if:當分支超過三個或涉及模式解構時,match更具可讀性。 - 避免副作用:盡量不要在條件判斷內執行副作用(如 I/O),以免產生不易預測的行為。
- 利用編譯期檢查:
cfg!可在條件中直接使用,讓程式在不同平台自動調整。
實際應用場景
參數驗證
在函式入口檢查參數合法性,若不符合條件立即回傳錯誤或預設值。fn set_volume(level: i32) -> Result<(), &'static str> { if !(0..=100).contains(&level) { Err("音量必須在 0~100 之間") } else { // 設定音量的實作 Ok(()) } }功能切換(Feature Flag)
依據環境變數或設定檔啟用/停用特定功能。let debug_mode = std::env::var("DEBUG").unwrap_or_default() == "1"; if debug_mode { println!("除錯模式已啟用"); }錯誤類型分流
在網路服務或 CLI 工具中,根據錯誤類別回傳不同的錯誤碼或訊息。fn exit_code(err: &str) -> i32 { if err.contains("not found") { 2 } else if err.contains("permission") { 3 } else { 1 } }跨平台資源載入
根據作業系統載入不同的檔案路徑或庫。let config_path = if cfg!(target_os = "windows") { "C:\\ProgramData\\myapp\\config.toml" } else { "/etc/myapp/config.toml" };資料分析中的分段統計
依年齡、收入等欄位將資料分組,計算各組的統計值。fn age_group(age: u8) -> &'static str { if age < 20 { "青少年" } else if age < 40 { "青年" } else if age < 60 { "中年" } else { "長者" } }
總結
if、else if、else在 Rust 中是表達式,可直接產生值並賦予變數或回傳。- 每個分支必須回傳相同型別,否則編譯會失敗。
- 使用
if let可以簡化單一模式的匹配;若分支較多,match更適合。 - 常見陷阱包括型別不一致、忘記
else、過度巢狀等,遵守最佳實踐可提升程式可讀性與安全性。 - 在實務開發中,條件判斷廣泛應用於 參數驗證、功能切換、錯誤處理、跨平台支援 等情境。
掌握了這些概念與技巧後,你就能在 Rust 程式中靈活運用條件判斷,寫出既安全又易於維護的程式碼。祝你在 Rust 的旅程中玩得開心,寫出更好的程式!