Day 7:第七週總結練習

學習目標

  • 整合 Result、?、自訂錯誤、panic 決策
  • 寫一個會讀檔、解析、處理錯誤的程式

今日重點

本週回顧

  1. Result?
  2. 自訂錯誤 + From 轉換
  3. std::error::Error trait、Box
  4. Result vs panic 決策
  5. expect / unwrap、#[should_panic]

綜合練習:設定檔解析器

use std::collections::HashMap;
use std::fs;

#[derive(Debug)]
enum ConfigError {
    Io(std::io::Error),
    MalformedLine(String),
}

impl From<std::io::Error> for ConfigError {
    fn from(e: std::io::Error) -> Self { ConfigError::Io(e) }
}

impl std::fmt::Display for ConfigError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            ConfigError::Io(e) => write!(f, "IO error: {}", e),
            ConfigError::MalformedLine(l) => write!(f, "格式錯誤: {}", l),
        }
    }
}

fn load_config(path: &str) -> Result<HashMap<String, String>, ConfigError> {
    let content = fs::read_to_string(path)?;   // io 錯自動轉

    let mut map = HashMap::new();
    for line in content.lines() {
        let line = line.trim();
        if line.is_empty() || line.starts_with('#') {
            continue;   // 跳過空行與註解
        }
        let Some((k, v)) = line.split_once('=') else {
            return Err(ConfigError::MalformedLine(line.to_string()));
        };
        map.insert(k.trim().to_string(), v.trim().to_string());
    }
    Ok(map)
}

fn main() -> Result<(), ConfigError> {
    let config = load_config("app.config")?;
    for (k, v) in &config {
        println!("{} = {}", k, v);
    }
    Ok(())
}

產生一個 app.config 檔案(內容 ex debug=trueport=8080)測試。

挑戰

  • 加一個「重複 key 報錯」的行為。
  • 思考哪些地方該用 Result、哪些其實該 panic(例如:config 檔案天生就壞 → 傳給呼叫端比較好)。

自我檢查

  • 能全文使用 ? + 自訂錯誤
  • 會設計「回傳 Result 的 main」
  • 能判斷 Result vs panic
  • 對錯誤處理有完整把握

週總結

錯誤處理是工程品質的核心。你已能寫出穩健、可讀的錯誤處理程式。

下一週進入並發(執行緒、訊息傳遞、共享狀態)。