錯誤處理在生產級別的**中一直都是乙個重點。在原型階段,愉快地使用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...