iT邦幫忙

2025 iThome 鐵人賽

DAY 5
0
Rust

Rust 後端入門系列 第 5

Day 5 Rust錯誤處理: Option 與 Result

  • 分享至 

  • xImage
  •  

我們將討論Rust中的錯誤處理。它是Rust中的一個重要的概念。

如果你曾經在其他程式語言中遇到過空指標錯誤(NullPointerException),那麼我相信你會喜歡Rust處理錯誤的方式。

為什麼要學習Result和Option?

在其他程式語言中的錯誤處理流程,可能是這樣的:

  • 函數可能回傳null,但不知道何時會回傳null。
  • 又或者是:錯誤可能發生在任何地方,導致程式終止。

所以需要檢查每一個可能會導致錯誤的地方。

Rust說:我們比其他程式語言更加優雅。Rust透過Result和Option使錯誤處理明瞭、更容易找到出錯的部分。

Option

Option的作用是處理接收可能不存在的數值,它有兩種變體:

  • Some(T):包含一個T資料型態的數值
  • None:沒有值存在

使用範例

我們模擬一個根據id查詢用戶名稱的程式,如果是經常撰寫後端程式的朋友肯定很熟悉,肯定開始準備用if-else來分開處理存在和不存在。

在Rust中,我們組合Option跟match就能簡潔的完成這個功能。

fn find_user_by_id(id: u32) -> Option<String> {
    match id {
        1 => Some("user1".to_string()),
        2 => Some("user2".to_string()),
        _ => None,
    }
}

fn main() {
    let user = find_user_by_id(1);
    match user {
        Some(name) => println!("找到用戶:{}", name),
        None => println!("用戶不存在"),
    }
}

Option的使用時機

  • 資料庫查詢時:可能找不到對應的記錄。
  • 讀取陣列資料時:可能超過陣列的範圍,導致錯誤發生。

Result

Result<T, E>表示有可能會出錯,但是也有可能不會出現錯誤,可以用這兩個方式取得結果或是錯誤訊息:

  • Ok(T):成功執行,沒有錯誤,取得資料型態為T的結果。
  • Err(E):出現錯誤,E是錯誤訊息。

使用範例

以下是一個讀取檔案的範例,通常情況下,可以正常讀取並顯示檔案內容,不過也有可能檔案不存在或讀取錯誤,要顯示對應的錯誤訊息,因此需要使用Result。

use std::fs::File;
use std::io::{self, Read};

fn read_file(filename: &str) -> Result<String, std::io::Error> {
    let file_result = File::open(filename);
    let mut file = match file_result {
        Ok(file) => file,
        Err(error) => return Err(error),
    };

    let mut contents = String::new();
    let read_result = file.read_to_string(&mut contents);
    match read_result {
        Ok(_) => Ok(contents),
        Err(error) => Err(error),
    }
}

fn main() {
    match read_file("test.txt") {
        Ok(content) => println!("檔案內容:{}", content),
        Err(error) => println!("讀取失敗:{}", error),
    }
}

Result的使用時機

  • 讀寫檔案時:可能因為權限不足或檔案不存在,引起錯誤。
  • 連接資料庫時:可能因為連接失敗,或是發生SQL相關的錯誤。

? 關鍵字

讀取檔案的範例其實可以寫得更加簡潔,只要我們使用 ? 關鍵字。

use std::fs::File;
use std::io::{self, Read};

fn read_file(filename: &str) -> Result<String, std::io::Error> {
    let mut file = File::open(filename)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

fn main() {
    match read_file("test.txt") {
        Ok(content) => println!("檔案內容:{}", content),
        Err(error) => println!("讀取失敗:{}", error),
    }
}

可以將新舊程式碼互相對比,就可以看到match的部分被縮短成一個 ? ,就能完成優雅的錯誤傳遞。


上一篇
Day 4 Rust 所有權與借用
下一篇
Day 6 Vec、HashMap 與疊代器
系列文
Rust 後端入門9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言