Rust Crate 使用:error-chain

Error-chain

Github

crates.io

前言

錯誤和異常傻傻分不清,這裡統稱為錯誤吧。Rust 錯誤分為兩大類:可恢復不可恢復的錯誤

  • 可恢復的錯誤,例如一個文件沒有發現錯誤,這時合理的向用戶報告的問題和重試操作。
  • 不可恢復的錯誤總是就是不可恢復了,比如數組的越界訪問。

大多語言,例如在c++對上述兩類錯誤沒有嚴格區分,可以使用相同的處理方式,返回值拋異常,這兩種方式在業界一直爭論不休,分不清孰好孰壞。

然鵝 Rust 沒有異常,它的類型Result<T,E>用於處理可恢復錯誤panic! 宏用於處理一個不可恢復的錯誤,將立即停止執行程序。

panic! 的處理方式在human-panic文章中提及如何處理。本文主要講解Result<T,E>類的錯誤處理。

介紹

error_chain目標是提供統一的,可靠的錯誤處理方式。

為什麼使用它

  • error-chain容易配置,以最小的代價處理錯誤。
  • 對原生錯誤基本上不需要實現From介面就能使用 ?
  • 實現簡單,不需要額外代碼
  • 正確管理錯誤的原因。

原生操作

錯誤處理編程三步驟: 1. 定義自己的錯誤類型 2. 實現錯誤提示函數 3. 關聯外部錯誤類型

首先,實現我們的自定義類型。

/// 第一步,自定義錯誤類型
#[derive(Debug)]
enum MyError {
Single,
Duple(String),
Multi(u32, Vec<u32>),
IO(io::Error),
}

/// 第二步,實現列印函數
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
}
}

實現上面兩步,我們可以返回錯誤,並顯示錯誤信息。當然,我們不能僅限於此,當我使用系統庫或者第三方庫時,通常會有其他錯誤類型,需要轉換成MyError類型方便管理。

/// 第三步,實現其他錯誤類型轉換
impl From<io::Error> for MyError {
fn from(error: io::Error) -> Self {
MyError::IO(error)
}
}

完成上述三步,我們可以輕鬆處理錯誤了。 當我們讀取不存在的文件返回了一個io錯誤,把它轉換成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!宏,幫我們實現了什麼?引入官方例子:

// Well 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! { }
}

官方說幫我們實現了Error結構體,ErrorKind枚舉,ResultExt結構體,Result別名。 現在用error-chain!重新實現先前的例子。

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類似實現了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

推薦閱讀:

TAG:Rust(編程語言) |