Day 6:Result 與自訂錯誤

學習目標

  • 理解 Result 的用途
  • 用 match / 方法處理成功或失敗
  • 定義帶資訊的自訂錯誤列舉

今日重點

Result 是內建的

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

Result 用於「可能失敗」的運算,Err 攜帶錯誤資訊。

基本用法

fn find_user(id: u32) -> Result<String, String> {
    if id == 1 {
        Ok(String::from("John"))
    } else {
        Err(format!("User {} not found", id))
    }
}

fn main() {
    match find_user(1) {
        Ok(name) => println!("Found: {}", name),
        Err(msg) => println!("Error: {}", msg),
    }
}

自訂錯誤列舉

#[derive(Debug)]
enum AppError {
    NotFound(String),
    PermissionDenied,
    InvalidInput(String),
}

impl std::fmt::Display for AppError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            AppError::NotFound(msg) => write!(f, "Not found: {}", msg),
            AppError::PermissionDenied => write!(f, "Permission denied"),
            AppError::InvalidInput(msg) => write!(f, "Invalid input: {}", msg),
        }
    }
}

常用方法

  • unwrap() / expect(msg):直接取 Ok,錯就 panic
  • unwrap_or(default):Err 給預設值
  • map_err(f):轉換錯誤型別
  • ?:自動傳播錯誤(第 7 週深入)

練習

#[derive(Debug)]
enum ConfigError { MissingKey(String), BadFormat(String) }

fn load_config(text: &str) -> Result<Vec<(String, String)>, ConfigError> {
    let mut out = vec![];
    for line in text.lines() {
        let Some((k, v)) = line.split_once('=') else {
            return Err(ConfigError::BadFormat(line.to_string()));
        };
        out.push((k.to_string(), v.to_string()));
    }
    Ok(out)
}
1. 實作以上解析,分別測成功與失敗(格式錯誤)。 2. 用 Result 加上 unwrap_or 提供預設設定。

自我檢查

  • 知道他回 Ok/Err 就是 Result
  • 能定義帶欄位的自訂錯誤
  • 會實作 Display 給自訂錯誤
  • 知道 unwrap_or / map_err 的用途

深入連結

  • The Book 第 9 章「Recoverable Errors with Result」