Rust每週一庫 failure 錯誤處理庫

2021-10-04 12:23:10 字數 3082 閱讀 5658

錯誤處理在生產級別的**中一直都是乙個重點。在原型階段,愉快地使用unwrap可以確保思路和精力被集中用在業務邏輯開發上。不過對於最終要上線的**,優雅的處理錯誤卻是至關重要的。原生rust錯誤處理的工具有std::error::error(一般我們會看到box的形式),?操作符以及enum供我們自定義錯誤型別。這本身就可以作為乙個專題來討論。而今天我們就來簡單介紹一下failure庫以及其背後的錯誤處理哲學。

failure是rust-lang-nursery下的乙個庫,可以說是根正苗紅的rust庫了。其目標是取代基於std::eror::error的錯誤處理。

failure有兩個核心元件

fail trait被用來取代std::error::error。它提供了backtrace和cause方法去獲取錯誤的資訊。也支援將錯誤包裝在上下文(context)中。所有新的錯誤型別都應該實現該trait。對於乙個實現了fail的fail,我們可以逐層列印出錯誤鏈條

let mut fail: &fail = err;

while let some(cause) = fail.cause() ", cause);

fail = cause;

}

也可以列印出backtrace錯誤回溯

if let some(bt) = err.cause().and_then(|cause| cause.backtrace()) ", bt)

}

也可以引入resultext從而給錯誤加入上下文(context)以分辨想通的錯誤。比如為了區分io錯誤,我們可以:

use failure::resultext;

let mut file = file::open(cargo_toml_path).context("missing cargo.toml")?;

file.read_to_end(&buffer).context("could not read cargo.toml")?;

一般來說fail可以方便的被derive出來,只需要自己去實現display即可

extern crate failure;

#[macro_use] extern crate failure_derive;

use std::fmt;

#[derive(fail, debug)]

struct myerror;

impl fmt::display for myerror

}

而只要實現了fail trait的型別,都可以通過?被轉化成error。比如下邊的例子中,io錯誤和json錯誤都被轉化成了result中的error

#[derive(deserialize)]

struct object

impl object

}

簡單說來,有如下幾個模式可供選擇:

這是乙個比較簡便的方法,推薦在原型階段使用。format_err巨集可以很容易的生成乙個error。

fn check_range(x: usize, range: range) -> result is below {}", x, range.start));

}if x >= range.end is above {}", x, range.end));

}ok(x)

}

除了原型階段之外,當錯誤非常罕見以及對錯誤的處理只能侷限於列印的情況下,可以使用這個模式。很明顯,在這個模式下能對返回的錯誤做出的操作非常有限。如果需要知道錯誤的具體型別/內容,還需要做字串匹配。

接下來就是自定義實現了fail trait的錯誤,這可以通過derive巨集很容易的實現。這樣做有三大好處:

#[derive(fail, debug)]

#[fail(display = "input was invalid utf-8 at index {}", index)]

pub struct utf8error

在對待從依賴以外的部分返回的錯誤是,可以使用這一策略。

當乙個函式中會返回多種錯誤時可以使用這一模式,其具有以下特點:

use std::io;

use std::io::bufread;

use failure::error;

use failure::err_msg;

fn my_function() -> result<(), error>

if !line.starts_with("$")

println!("{}", &line[1..]);

}ok(())

}

一般來說當你不需要析構返回的錯誤時可以採用這一模式。包括:

#[derive(debug)]

struct myerror

#[derive(copy, clone, eq, partialeq, debug, fail)]

enum myerrorkind

但是你必須自己實現fail,以及提供一些轉換函式

impl fail for myerror 

fn backtrace(&self) -> option<&backtrace>

}impl display for myerror

}impl myerror

}impl fromfor myerror

}}impl from> for myerror

}}

這樣你就可以使用把errorkind注入到使用的函式中

perform_some_io().context(errorkind::networkfailure)?;
當然你也可以直接丟擲錯誤

err(errorkind::domainspecificerror)?
該模式最適合處於中間層並且有許多依賴的生產環境**。

錯誤的坑真是深似水,這裡也只是對failure這一著名的錯誤處理庫做了初步的介紹,祝大家一起在錯誤中成長~

Rust每週一庫 hyper 底層http庫

現在說到寫應用,網路框架肯定是必不可少的。今天就給大家簡單介紹一下hyper。hyper是乙個偏底層的http庫,支援http 1和http 2,支援非同步rust,並且同時提供了服務端和客戶端的api支援。很多同學可能覺得既然hyper是個偏底層的框架,那是不是就不需要去了解了呢?首先很多上層的框...

Rust每週一庫 csv 檔案讀寫庫

這次搬運的庫是很多資料分析師 資料科學家 以及金融分析師常用的csv檔案庫。用rust實現的乙個高效能 靈活的csv讀寫器,支援serde.將以下配置加進你的cargo.toml dependencies csv 1.1 簡單示範如何從stdin讀取csv資料並通過stdout將每一條記錄列印出來。...

Rust每週一知 一種 Rust 設計模式

最近發現一種 rust 的設計模式,有點好玩,發出來大家 一下。示例如下 use std ops deref trait traitfoo struct a impl traitfoo for a struct b implb implderef for b trait traitbar struc...