【Rust錯誤處理】使用`thiserror`+`anyhow`來優(yōu)雅便捷地處理錯誤


title: "【Rust錯誤處理】使用thiserror+anyhow來優(yōu)雅便捷地處理錯誤"
date: 2020-03-08T17:37:00+08:00
description: ""
featured_image: ""
categories: "Rust"
tags: ["錯誤處理"]


錯誤處理琅催,一直是編程語言的一個設(shè)計難點柳譬,各種編程語言的錯誤處理機制都不盡相同完箩,并且各有優(yōu)劣粥诫,Rust也不例外籍滴。

Rust使用Result這個enum來代表正確或錯誤的情況待逞,思路來源于HaskellOCaml等函數(shù)式語言轩缤,可以說是十分的優(yōu)雅转唉,特別體現(xiàn)在對OptionIterator的交互上皮钠,但是對于新人入門來說需要一定的學(xué)習(xí)成本。

從我自身的使用情況來說赠法,我總結(jié)了一下目前Rust(版本1.41.1)的錯誤處理的幾個缺點:

  1. 多種類型的Error在同一個函數(shù)中需要處理時麦轰,必須要有一個共同的可以IntoError類型作為函數(shù)返回值,比如下面的代碼:

    fn foo() -> Result<(), FooError> {
        let one: Result<(), OneError> = fn_one();
        one?;
    
        let two: Result<(), TwoError> = fn_two();
        two?;
    
        Ok(())
    }
    

    那么FooError必須有實現(xiàn)From<OneError>From<TwoError>砖织,慣常的做法是寫一個enum將所有的錯誤都封裝起來款侵,并且實現(xiàn)DisplayDebug侧纯、Error還有From<T>這幾個trait新锈,手寫的話比較枯燥乏味。

  2. Error trait的backtrace還未穩(wěn)定眶熬,雖然說backtrace對性能會有損耗妹笆,但是沒有backtrace在遇到錯誤拋出的時候,如果錯誤沒有一些明確的信息娜氏,就很難定位到是哪里的代碼拋的這個錯誤拳缠,特別是對于第三方庫拋的錯誤,對于開發(fā)調(diào)試和生產(chǎn)排查問題都造成了不便贸弥,在Fix the Error trait這個RFC里面有提出窟坐。


針對第一點情況,Rust界的大佬dtolnay設(shè)計了兩個crate:thiserroranyhow绵疲。在這之前已經(jīng)有很多提升錯誤處理的庫了哲鸳,比如failureerror-chainquickerror等等盔憨,這些庫我都使用過帕胆,而且這些庫都有一定程度的互相借鑒,但最后最終還是解決thiserror+anyhow是最易用和實用的般渡。

注意事項:thiserror是給lib使用的懒豹,而anyhow是給bin程序使用芙盘,當(dāng)然bin程序可以使用thiser+anyhow,但是切記anyhow不要在lib里面使用脸秽。

這兩個crate的使用方法在README中也說得很清楚明白了儒老,所以下面只是簡單得闡述一下:

thiserror

復(fù)制粘貼的thiserror示例:

use thiserror::Error;

#[derive(Error, Debug)]
pub enum DataStoreError {
    #[error("data store disconnected")]
    Disconnect(#[from] io::Error),
    #[error("the data for key `{0}` is not available")]
    Redaction(String),
    #[error("invalid header (expected {expected:?}, found {found:?})")]
    InvalidHeader {
        expected: String,
        found: String,
    },
    #[error("unknown data store error")]
    Unknown,
}

這個其實就是用enum封裝的思路,但是因為是用derive macro來自動生成的记餐,節(jié)省了很多的時間和敲鍵成本驮樊,也沒有那么無聊。

anyhow

復(fù)制粘貼的anyhow示例:

use anyhow::Result;

fn get_cluster_info() -> Result<ClusterMap> {
    let config = std::fs::read_to_string("cluster.json")?;
    let map: ClusterMap = serde_json::from_str(&config)?;
    Ok(map)
}

這個就更加簡潔了片酝,直接將anyhow::Result作為返回值就可以了囚衔,因為它直接實現(xiàn)了From<E> where E: Error,所以就不需要再維護(hù)一個enum類型了雕沿,但是注意只有在bin程序里面才可以這么搞练湿,因為在lib里面這么做的話,別人在使用的時候想特別處理某種情況的錯誤审轮,只能通過downcast來處理肥哎,這個設(shè)計是很不友好的。

在bin程序里面如果有一點需要特別處理的錯誤疾渣,比如后端接口中的用戶權(quán)限失敗這種錯誤篡诽,是需要明確標(biāo)記出來(區(qū)分錯誤碼等),讓前端彈出登錄框這種需求的榴捡,這里就可以將thiserroranyhow::Result相結(jié)合使用了:

復(fù)制粘貼的thiserror示例:

#[derive(Error, Debug)]
pub enum MyError {
    ...

    #[error(transparent)]
    Other(#[from] anyhow::Error),  // source and Display delegate to anyhow::Error
}

對于需要特別對待的錯誤杈女,則手工去用thiserror維護(hù),對于無關(guān)重要的錯誤吊圾,則統(tǒng)一用Other去包裝就可以了碧信。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市街夭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌躏筏,老刑警劉巖板丽,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異趁尼,居然都是意外死亡埃碱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門酥泞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來砚殿,“玉大人,你說我怎么就攤上這事芝囤∷蒲祝” “怎么了辛萍?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長羡藐。 經(jīng)常有香客問我贩毕,道長,這世上最難降的妖魔是什么仆嗦? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任辉阶,我火速辦了婚禮,結(jié)果婚禮上瘩扼,老公的妹妹穿的比我還像新娘谆甜。我一直安慰自己,他們只是感情好集绰,可當(dāng)我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布规辱。 她就那樣靜靜地躺著,像睡著了一般倒慧。 火紅的嫁衣襯著肌膚如雪按摘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天纫谅,我揣著相機與錄音炫贤,去河邊找鬼。 笑死付秕,一個胖子當(dāng)著我的面吹牛兰珍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播询吴,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼掠河,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了猛计?” 一聲冷哼從身側(cè)響起唠摹,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奉瘤,沒想到半個月后勾拉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡盗温,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年藕赞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卖局。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡斧蜕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出砚偶,到底是詐尸還是另有隱情批销,我是刑警寧澤洒闸,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站风钻,受9級特大地震影響顷蟀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜骡技,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一鸣个、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧布朦,春花似錦囤萤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至唆途,卻和暖如春富雅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肛搬。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工没佑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人温赔。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓蛤奢,卻偏偏與公主長得像,于是被迫代替她去往敵國和親陶贼。 傳聞我的和親對象是個殘疾皇子啤贩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容