我們將討論Rust中的錯誤處理。它是Rust中的一個重要的概念。
如果你曾經在其他程式語言中遇到過空指標錯誤(NullPointerException),那麼我相信你會喜歡Rust處理錯誤的方式。
在其他程式語言中的錯誤處理流程,可能是這樣的:
所以需要檢查每一個可能會導致錯誤的地方。
Rust說:我們比其他程式語言更加優雅。Rust透過Result和Option使錯誤處理明瞭、更容易找到出錯的部分。
Option的作用是處理接收可能不存在的數值,它有兩種變體:
我們模擬一個根據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!("用戶不存在"),
}
}
Result<T, 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),
}
}
讀取檔案的範例其實可以寫得更加簡潔,只要我們使用 ? 關鍵字。
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的部分被縮短成一個 ? ,就能完成優雅的錯誤傳遞。