Rust中錯誤處理的最簡單指南
Rust 中有兩種型別的錯誤:
- 不可恢復的錯誤(例如,未檢查的越界陣列訪問)
- 可恢復的錯誤(例如,功能失敗)
不可恢復的錯誤
對於無法處理且會使您的程式進入不可恢復狀態的錯誤,我們使用panic! 宏。
fn encrypt(key: &[u8], data: &[u8]) -> Vec<u8> { if key.len() != 32 { panic!("encrypt: key length is invalid"); } // ... } |
另一種觸發 a 的方法panic是使用assert! 宏。
fn encrypt(key: &[u8], data: &[u8]) -> Vec<u8> { assert!(key.len() == 32, "encrypt: key length is invalid"); // ... } |
話雖如此,在 Rust 中處理錯誤非常符合人體工程學,所以我認為沒有充分的理由去故意panic.
可恢復的錯誤
應處理的錯誤將與Result 列舉一起返回。
pub enum Result<T, E> { Ok(T), Err(E), } |
例如:
// Here, our error type is `String` fn ultimate_answer(guess: i64) -> Result<(), String> { if guess == 42 { return Ok(()); } return Err("Wrong answer".to_string()); } |
現在,將 aString作為錯誤返回並不是很有用。事實上,同一個函式可能會返回許多不同的錯誤,因此越來越難以精確處理它們:
fn ultimate_answer(guess: i64) -> Result<(), String> { if guess == 42 { return Ok(()); } else if guess > 39 && guess <= 41 { return Err("A little bit more".to_string()); } else if guess <= 45 && guess > 42 { return Err("A little bit less".to_string()); } return Err("Wrong answer".to_string()); } |
或者,許多不同的函式可以返回相同的錯誤:
fn do_something() -> Result<(), String> { // ... return Err("Something went wrong".to_string()); } fn do_something_else() -> Result<(), String> { // ... return Err("Something went wrong".to_string()); } fn do_another_thing() -> Result<(), String> { // ... return Err("Something went wrong".to_string()); } |
這是我們需要定義自己的Error列舉的地方。通常,我們Error透過 crate 定義 1 個列舉。
pub enum Error { WrongAnswer, More, Less, } fn ultimate_answer(guess: i64) -> Result<(), Error> { if guess == 42 { return Ok(()); } else if guess > 39 && guess <= 41 { return Err(Error::More); } else if guess <= 45 && guess > 42 { return Err(Error::Less); } return Err(Error::WrongAnswer); } |
然後,我們可能希望為每個錯誤案例標準化錯誤訊息。為此,社群選擇了thiserror crate。
#[derive(thiserror::Error)] pub enum Error { #[error("Wrong answer")] WrongAnswer, #[error("A little bit more")] More, #[error("A little bit less")] Less, } |
多虧了thiserror::Error,您的Error列舉現在實現了std::error::Error特徵,因此也實現了Debug和Display特徵。
然後我們可以處理一個潛在的錯誤match。
fn question() -> Result<(), Error> { let x = // ... match ultimate_answer(x) { Ok(_) => // do something Err(Error::More) => // do something Err(Error::Less) => // do something Err(Error::WrongAnswer) => // do something } // ... } |
或者,處理錯誤的最常見方法是使用?.
fn question() -> Result<(), Error> { let x = // ... ultimate_answer(x)?; // if `ultimate_answer` returns an error, `question` stops here and returns the error. // ... } |
這是一個快捷方式:
fn question() -> Result<(), Error> { let x = // ... match ultimate_answer(x) { Ok(_) => {}, Err(err) => return Err(err.into()), }; // ... } |
錯誤轉換
您的程式或庫可能會使用許多依賴項,每個依賴項都有自己的錯誤型別,但為了能夠使用?,您的Error型別需要為依賴項的錯誤型別實現From特徵。
#[derive(Error, Debug, Clone)] pub enum Error { #[error("Internal error.")] Internal(String), #[error("Not found.")] NotFound, #[error("Permission Denied.")] PermissionDenied, #[error("Invalid argument: {0}")] InvalidArgument(String), } impl std::convert::From<std::num::ParseIntError> for Error { fn from(err: std::num::ParseIntError) -> Self { Error::InvalidArgument(err.to_string()) } } impl std::convert::From<sqlx::Error> for Error { fn from(err: sqlx::Error) -> Self { match err { sqlx::Error::RowNotFound => Error::NotFound, _ => Error::Internal(err.to_string()), } } } |
最後,您可以使用.unwrap()和.expect()對可恢復的錯誤感到恐慌
fn do_something() -> Result<(), Error> { // ... } fn main() { // panic if do_something returns Err(_) do_something().unwrap(); } // or fn main() { // panic if do_something returns Err(_) with the message below do_something().expect("do_something returned an error"); } |
相關文章
- 學習Rust 錯誤處理Rust
- rust學習十、異常處理(錯誤處理)Rust
- 簡單介紹Python 處理錯誤的原則Python
- grpc中的錯誤處理RPC
- Restful API 中的錯誤處理RESTAPI
- 【譯】RxJava 中的錯誤處理RxJava
- 談談RxSwift中的錯誤處理Swift
- 應用中的錯誤處理概述
- Bash 指令碼中的錯誤處理指令碼
- Go 為什麼不像 Rust 用 ?!做錯誤處理?GoRust
- 包含(處理)HTML的最簡單方法包括HTML
- 錯誤處理
- go的錯誤處理Go
- axios 的錯誤處理iOS
- 從錯誤處理看 Rust 的語言和 Go 語言的設計RustGo
- 如何在 Go 中優雅的處理和返回錯誤(1)——函式內部的錯誤處理Go函式
- Python錯誤處理Python
- PHP 錯誤處理PHP
- php錯誤處理PHP
- Go 錯誤處理Go
- 錯誤處理:如何通過 error、deferred、panic 等處理錯誤?Error
- openGauss 處理錯誤表
- 【翻譯】在Spring WebFlux中處理錯誤SpringWebUX
- 請教 Element 的錯誤處理
- 簡單的字串處理字串
- Python錯誤處理和異常處理(二)Python
- 前端的水平線,錯誤處理和除錯前端除錯
- Oracle異常錯誤處理Oracle
- 淺談前端錯誤處理前端
- ORACLE 異常錯誤處理Oracle
- PHP 核心特性 - 錯誤處理PHP
- 15-錯誤處理(Error)Error
- Go語言之錯誤處理Go
- laravel9 錯誤處理Laravel
- 如何優雅的在Golang中進行錯誤處理Golang
- JavaScript 中遇到的錯誤問題,該怎麼處理?JavaScript
- 基於 React Redux 的錯誤處理ReactRedux
- Go 的錯誤處理策略 筆記Go筆記