Error-chain
前言
錯誤和異常傻傻分不清彬坏,這里統(tǒng)稱為錯誤吧。Rust 錯誤分為兩大類:可恢復和不可恢復的錯誤呻畸。
- 可恢復的錯誤防嗡,例如一個文件沒有發(fā)現(xiàn)錯誤,這時合理的向用戶報告的問題和重試操作淮逊。
- 不可恢復的錯誤總是就是不可恢復了,比如數(shù)組的越界訪問催首。
大多語言,例如在c++對上述兩類錯誤沒有嚴格區(qū)分泄鹏,可以使用相同的處理方式郎任,返回值和拋異常,這兩種方式在業(yè)界一直爭論不休备籽,分不清孰好孰壞舶治。
然鵝 Rust 沒有異常,它的類型Result<T,E>
用于處理可恢復錯誤; panic!
宏用于處理一個不可恢復的錯誤车猬,將立即停止執(zhí)行程序霉猛。
panic!
的處理方式在human-panic文章中提及如何處理。本文主要講解Result<T,E>
類的錯誤處理珠闰。
介紹
error_chain
目標是提供統(tǒng)一的惜浅,可靠的錯誤處理方式。
為什么使用它
-
error-chain
容易配置铸磅,以最小的代價處理錯誤赡矢。 - 對原生錯誤基本上不需要實現(xiàn)
From
接口就能使用?
杭朱。 - 實現(xiàn)簡單阅仔,不需要額外代碼
- 正確管理錯誤的原因。
操作
原生操作
錯誤處理編程三步驟:
- 定義自己的錯誤類型
- 實現(xiàn)錯誤提示函數(shù)
- 關聯(lián)外部錯誤類型
首先弧械,實現(xiàn)我們的自定義類型八酒。
/// 第一步,自定義錯誤類型
#[derive(Debug)]
enum MyError {
Single,
Duple(String),
Multi(u32, Vec<u32>),
IO(io::Error),
}
/// 第二步刃唐,實現(xiàn)打印函數(shù)
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
MyError::Single => write!(f, "Single Error"),
MyError::Duple(ref err) => write!(f, "Dutple {} Error", err),
MyError::Multi(ref len, ref data) => write!(f, "Multi len {} data {:?} Error", len, data),
MyError::IO(ref e) => write!(f, "{}", e)
}
}
}
/// 錯誤通用化
impl std::error::Error for MyError {
fn description(&self) -> &str {
"MyError"
}
fn cause(&self) -> Option<&std::error::Error> {
None
}
}
實現(xiàn)上面兩步羞迷,我們可以返回錯誤界轩,并顯示錯誤信息。當然衔瓮,我們不能僅限于此浊猾,當我使用系統(tǒng)庫或者第三方庫時,通常會有其他錯誤類型热鞍,需要轉(zhuǎn)換成MyError
類型方便管理葫慎。
/// 第三步,實現(xiàn)其他錯誤類型轉(zhuǎn)換
impl From<io::Error> for MyError {
fn from(error: io::Error) -> Self {
MyError::IO(error)
}
}
完成上述三步薇宠,我們可以輕松處理錯誤了偷办。 當我們讀取不存在的文件返回了一個io
錯誤,把它轉(zhuǎn)換成MyError
類型澄港。
fn read() -> std::result::Result<(), MyError> {
let _file = File::open("unknown_file.txt")?;
std::result::Result::Ok(())
}
fn main() {
match read() {
std::result::Result::Ok(_) => println!("No Error"),
std::result::Result::Err(e) => println!("{}", e),
}
}
Error-chain操作
怎么讓代碼更加簡潔呢椒涯?這時就需要用到error-chain
了。它提供了error-chain!
宏回梧,幫我們實現(xiàn)了什么废岂?引入官方例子:
// We'll put our errors in an `errors` module, and other modules in
// this crate will `use errors::*;` to get access to everything
// `error_chain!` creates.
mod errors {
// Create the Error, ErrorKind, ResultExt, and Result types
error_chain! { }
}
官方說幫我們實現(xiàn)了Error
結(jié)構體,ErrorKind
枚舉狱意,ResultExt
結(jié)構體泪喊,Result
別名。
現(xiàn)在用error-chain!
重新實現(xiàn)先前的例子髓涯。
error_chain! {
foreign_links {
Io(::std::io::Error) #[doc = "Error during IO"];
}
errors {
Single {
description("MyError!")
display("Single Error")
}
Duple(t: String) {
description("MyError!")
display("Dutple {} Error", t)
}
Multi(len: u32, data: Vec<u32>) {
description("MyError!")
display("Multi len {} data {:?} Error", len, data)
}
}
}
foreign_links
類似實現(xiàn)了IO(io::Error)
枚舉類型袒啼,以及它的From
接口。
嘗試錯誤:
fn read_file() -> Result<()> {
let _file = File::open("unknown_file.txt")?;
std::result::Result::Ok(())
}
fn main() {
match read_file() {
std::result::Result::Ok(_) => println!("No Error"),
std::result::Result::Err(e) => println!("{}", e),
}
}
資料
announcing-error-chain-a-library-for-consistent-and-reliable-rust-error-handling
starting-with-error-chain