iT邦幫忙

2025 iThome 鐵人賽

DAY 14
0
Rust

Rust 30 天養成計畫:從零到 CLI 專案系列 第 14

Day 14:Result 與錯誤處理

  • 分享至 

  • xImage
  •  

1. 為什麼需要 Result
在 C/C++ 中,函數失敗時可能回傳 -1 或 NULL,但這種方式不直觀,也容易忘記檢查,Rust 提供 Result,明確表示可能成功 (Ok)或可能失敗 (Err)。

enum Result<T, E> {
    Ok(T),
    Err(E),
}

2. 基本範例

fn divide(a: i32, b: i32) -> Result<i32, String> {
    if b == 0 {
        Err(String::from("Cannot divide by zero"))
    } else {
        Ok(a / b)
    }
}

fn main() {
    let r1 = divide(10, 2);
    let r2 = divide(10, 0);

    println!("r1 = {:?}", r1);
    println!("r2 = {:?}", r2);
}

輸出:

r1 = Ok(5)
r2 = Err("Cannot divide by zero")

3. 使用 match 處理 Result

fn main() {
    let result = divide(10, 0);

    match result {
        Ok(value) => println!("Result = {}", value),
        Err(msg) => println!("Error: {}", msg),
    }
}

輸出:

Error: Cannot divide by zero

4. unwrap 與 expect
如果確定一定會成功,可以用 unwrap() 或 expect() 直接取值,程式錯誤時會 panic。

fn main() {
    let r = divide(10, 2).unwrap();
    println!("Result = {}", r);

    let r2 = divide(10, 0).expect("Division failed");
    println!("Result = {}", r2);
}

輸出(第二行會直接 panic):

Result = 5
thread 'main' panicked at 'Division failed: "Cannot divide by zero"'

5. ? 運算子
? 可以簡化錯誤傳遞,把錯誤往上丟。

use std::fs::File;

fn open_file() -> std::io::Result<File> {
    let f = File::open("hello.txt")?;  // 如果失敗,直接回傳 Err
    Ok(f)
}

這樣就不用一層層寫 match 來傳遞錯誤。

6. 學習心得與補充
今天學到的 Result 讓我覺得 Rust 在錯誤處理上比我以前寫過的語言更嚴謹。C++ 或 C 常用錯誤碼來代表失敗,但如果沒檢查就會直接出錯,Rust 則是用 Result 強迫我面對錯誤情況,不可能忽略。搭配 match 能寫得很完整,而 unwrap、expect 在我很確定的情況下又能省事,? 運算子讓錯誤傳遞變得簡潔。這讓我想到前幾天學的 Option,我覺得 Result 就像是更進一步把有沒有值擴充成成功或失敗,雖然覺得每次都要處理 Ok 和 Err 有點麻煩,但這樣的檢查其實會讓寫程式時更安心。


上一篇
Day 13:Option 與模式比對 (match)
下一篇
Day 15:泛型 (Generics)
系列文
Rust 30 天養成計畫:從零到 CLI 專案18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言