iT邦幫忙

2025 iThome 鐵人賽

DAY 22
0
Rust

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

Day 22:自訂錯誤型別與 Result 應用進階

  • 分享至 

  • xImage
  •  

1. 為什麼需要自訂錯誤
在前幾天的學習中,Result<T, E> 的 E 通常是 io::Error 或 String,但在實際專案裡,常會遇到多種錯誤來源(I/O、格式錯誤、邏輯錯誤等)。這時就需要自訂錯誤型別來整合不同錯誤情況,方便統一處理與擴充。

2. 定義自訂錯誤列舉

use std::fmt;
use std::io;

#[derive(Debug)]
enum AppError {
    Io(io::Error),
    Parse(std::num::ParseIntError),
}

impl fmt::Display for AppError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            AppError::Io(e) => write!(f, "IO error: {}", e),
            AppError::Parse(e) => write!(f, "Parse error: {}", e),
        }
    }
}

impl From<io::Error> for AppError {
    fn from(err: io::Error) -> AppError {
        AppError::Io(err)
    }
}

impl From<std::num::ParseIntError> for AppError {
    fn from(err: std::num::ParseIntError) -> AppError {
        AppError::Parse(err)
    }
}

3. 在函式中使用自訂錯誤

fn read_and_parse() -> Result<i32, AppError> {
    let content = std::fs::read_to_string("number.txt")?; // 可能回傳 io::Error
    let number: i32 = content.trim().parse()?;            // 可能回傳 ParseIntError
    Ok(number)
}

fn main() {
    match read_and_parse() {
        Ok(n) => println!("Read number: {}", n),
        Err(e) => println!("Error: {}", e),
    }
}

輸出:

Error: IO error: 系統找不到指定的檔案。 (os error 2)

或:

Error: Parse error: invalid digit found in string

4. 為什麼要實作 From 與 Display
From 的實作讓 ? 可以自動把不同錯誤轉換成你的自訂錯誤。Display 則讓錯誤能以人類可讀的方式輸出。
這樣一來,整個錯誤處理流程就更乾淨,不需要到處手動轉換錯誤型別或使用 unwrap。

5. 學習心得與補充
今天的學習讓我更深刻地體會到 Rust 的錯誤處理並不只是防呆機制,以前在 C++中,我常常只是單純地用 try-catch 包住錯誤,或回傳一個錯誤碼了事,但在 Rust 裡,錯誤本身被視為型別系統的一部分,設計得更具結構性。當我開始實作自己的 AppError 時,發現可以清楚地定義錯誤來源、讓編譯器協助我轉換錯誤,這種體驗比單純印錯誤訊息更可靠。再加上 ? 的自動傳遞機制,讓程式既安全又簡潔。透過這次練習,我開始理解 Rust 對錯誤處理的設計理念不只是防止出錯,而是幫助開發者更好地理解與掌握錯誤。


上一篇
Day 21:錯誤處理進階與 panic! 的使用
系列文
Rust 30 天養成計畫:從零到 CLI 專案22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言