Day 3:使用 std::error::Error trait
學習目標
- 認識 std::error::Error trait
- 用 Box
當泛用錯誤型別 - 用 map_err 加上下文資訊
今日重點
Error trait
std::error::Error是 Rust 標準錯誤的標記 trait。任何實作它的型別都可被當作「錯誤」。用Box<dyn Error>能容納不同型別的錯誤。
Box
use std::fs;
fn read_and_process(path: &str) -> Result<String, Box<dyn std::error::Error>> {
let contents = fs::read_to_string(path)?; // 自動轉成 Box<dyn Error>
Ok(contents.to_uppercase())
}
Box<dyn Error>缺點:失去具體型別,無法 match 特定錯誤。適合「只想向上拋、不細分」的場合,或簡潔的 main。
map_err + 上下文
fn process_data(path: &str) -> Result<String, Box<dyn std::error::Error>> {
let contents = fs::read_to_string(path)
.map_err(|e| format!("Failed to read {}: {}", path, e))?;
// 轉成 String 失去原錯誤型別,但保有可讀訊息
Ok(contents)
}
若要「帶 context 但保留原型別」,實務常用
anyhow::Context(第 10 週)。
練習
use std::fs;
// 1. 寫一個函式回傳 Result<u64, Box<dyn Error>>:讀檔後 parse 成數字
fn parse_number_file(path: &str) -> Result<u64, Box<dyn std::error::Error>> {
let content = fs::read_to_string(path)?;
let n: u64 = content.trim().parse()?; // 注意 String -> u64
Ok(n)
}
// 2. 在 main 中用 match 或 expect 呼叫
fn main() {
match parse_number_file("num.txt") {
Ok(n) => println!("Number: {}", n),
Err(e) => eprintln!("Error: {}", e),
}
}
自我檢查
- 知道 Error trait 是標準的標記
- 會用 Box
容納多種錯誤 - 用 map_err 提供上下文
- 知道 Box
的取捨(失去具體型別)
深入連結
- The Book 第 9 章「Taking Decisions on Error Handling」