Day 3:錯誤處理模式與設計

學習目標

  • 總結常用錯誤處理模式
  • 建立「錯誤為值」與「錯誤鏈」的思維
  • 應用 anyhow/thiserror 到實際結構

今日重點

模式一:錯誤恢復(recovery)

fn process_with_recovery(input: &str) -> Result<i32, String> {
    let number: i32 = input.trim().parse()
        .map_err(|e| format!("Parse error: {}", e))?;

    if number < 0 {
        return Err("Number must be positive".to_string());
    }
    Ok(number * 2)
}

模式二:錯誤鏈(error chain)——多用 ? 串接

fn chain_errors() -> Result<(), anyhow::Error> {
    let config = read_config()?;   // anyhow 版
    let data = load_data(&config)?;
    let result = process(data)?;
    save(result)?;
    Ok(())
}

用 anyhow 讓每一步的錯誤都往上傳,並保留原始來源。

模式三:錯誤作為值(error as value)

enum OperationResult {
    Success(String),
    Retry(String),
    Fail(String),
}

fn execute_operation() -> OperationResult {
    match do_something() {
        Ok(_) => OperationResult::Success("Done".to_string()),
        Err(e) => {
            if should_retry(&e) {
                OperationResult::Retry(e.to_string())
            } else {
                OperationResult::Fail(e.to_string())
            }
        }
    }
}

練習

use anyhow::{Result, Context};

struct Db { /* ... */ }

// 1. 寫一個三層函式:connect -> query -> save,全程用 anyhow
fn connect_db(url: &str) -> Result<()> {
    if url.is_empty() {
        anyhow::bail!("empty url");   // 直接製造錯誤
    }
    Ok(())
}

// 2. 用 anyhow::bail! 快速回傳錯誤
fn main() -> Result<()> {
    connect_db("").context("db setup")?;
    Ok(())
}

自我檢查

  • 熟練 pattern-rich 錯誤處理
  • 知道「錯誤為值」的設計
  • 會用 bail! 快速結束
  • 能組織多層錯誤

深入連結

  • anyhow(bail/Context)+ Rust error handling 社群文章