AD19 add pins to nets錯誤_為什么我認為Rust的Result錯誤處理方式不如Exception

61eed7b15f67f39343ca1892535e298f.png

由于是對技術的個人評判,歡迎理性討論。

我曾經也當過純函數式的腦殘粉,認為宇宙第一棒的代數數據結構用來處理錯誤,是無上的優雅和絕對的安全。一個看似人畜無害的接口拋出異常帶來的崩潰,是各類疑難雜癥的罪魁禍首。綜合起來,sum 類型相比 exception 的優勢有:

  • 不可變數據結構,purity is dignity;
  • 編譯檢查,必須處理,懶鬼退散,nobody can avoid it(異常經常不被妥善處理,直至發酵)
  • 可以寫在接口聲明中,并且嚴格規定了能產生的錯誤類型,anyone can hear the lion in the box(幾乎所有使用異常機制的語言都不要求標注異常,且一個函數可能拋出任何預料之外類型的異常);
  • 恢復錯誤時沒有exception那么大的開銷。可以用清晰簡潔的方法處理結果(unwrap, expect 等臨時方法,以及 and, or 等 combinator),并且能清楚地區分對待嚴重故障(panic)和預料之內的小問題(相對而言,捕捉異常要寫大堆 try ... catch 方塊,并且 exception 和 panic 一樣直接崩潰)

然而我越去實際使用這兩種方法,越發覺得 exception 要遠好于 sum type。原因如下:

  • 不強制要求處理異常,不是異常機制的問題,而是編譯器設計的問題。編譯器可以要求拋出異常的函數標注其拋出的異常類型,且調用這種函數的函數如果不處理這些異常,也必須標注這些異常的類型;
  • 如果強制處理異常,程序員就會抱怨 try ... catch 太多太煩。但這個麻煩也完全是設計問題。學習 Rust,同樣可以設計?運算符,用例如 foo()?,在 foo() 未拋出異常時直接使用結果,否則拋出異常給上層。unwrap, except之類的操作符也很容易實現,combinator 也不在話下;
  • 代碼量大了,到處都是 Result<T, E> 很讓人崩潰。很多很簡單的功能因為要適應其內部調用的函數或外部調用它的函數,也不得不給返回類型加上 Result。雖然為了安全,這是必要的開銷,但是這里面暗藏兩個問題:
    • 第1個,多寫那么多 Result,并不能在錯誤出現時讓我獲得更多。層層傳遞的 Result不會自動保存調用鏈條,無法像 exception 那樣從最深處 propogate(浮現?),保存直達病灶的堆棧信息。所以到需要輸出問題的時候,Result 只有一行,exception 有幾百行(或許編譯器也可以給Result做優化);
    • 第2個,Result 的 err type 實際上自縛手腳,把函數里可能產生的錯誤類型勒死在 err type 上。有時函數可能產生多種錯誤,卻非要用一個單獨的錯誤來統一,而這個單獨錯誤還得起一個面面俱到的名字,最后名字變得極為抽象,不明所以,最后就統一一種了事(雖然經常是工程設計問題,但很多時候身不由己)。相比而言,拋出何種 exception 完全由各個功能模塊自己決定,不需要相互約束。IO 產生的錯誤到外面還是 IOError,沒有轉換的開銷。
  • 最后一點,用了 Result,函數簽名不再純凈,我的工廠生產的啤酒不再是啤酒,而是Result<啤酒, 生產錯誤>,做出來的菜不再是菜,而是 Result<菜, 失敗料理>再也不能揮揮灑灑寫邏輯,思考也受處理 Result 阻礙。

所以我的提法是,不要拋棄異常。甚至,在有方便的異常處理操作符,且編譯器嚴格要求程序去處理之時,可以完全不需要 Result。作為例子,看以下 Rust 代碼,它是一個語法分析程序:

enum Token {/* 定義詞法分析的結果:token */
}enum Expr {/* 定義語法分析的結果:表達式 */
}/* 包含多種錯誤,但嚴格來說 EOF 并不算詞法錯誤 */
enum LexError {EOF,UnexpectedEOF,Lexeme(String),
}/* 從源碼獲取下一個 token */
fn next_token(source: &str) -> Result<Token, LexError> { /* ... */ }/* 不得不將 LexError 整合進來 */
enum ParseError {EOF,UnexpectedEOF,Syntax(String),
}/* 從源碼解析一個表達式,看起來還挺優雅,但有轉換開銷 */
fn parse(source: &str) -> Result<Expr, ParseError> {/* ... */match next_token(source) {Ok(token) => /* ... */,Err(LexError::EOF) => Err(ParseError::EOF),Err(LexError::UnexpectedEOF) => Err(ParseError::UnexpectedEOF),Err(LexError::Lexeme(msg)) => Err(ParseError::Syntax(msg)),}
}/* 事情剛開始麻煩起來 */
enum ParseFileError {Syntax(ParseError),IO(IOError),
}/* 從源文件路徑讀取源碼并解析成表達式,混入了 io::Error,可以看到判斷邏輯已十分復雜,很多時候程序員都直接 unwrap 了事 */
fn parseFile(path: &str) -> Result<Expr, ParseFileError> {let mut file = std::fs::File::open(path);if let Err(ioError) = file {return ParseFileError::IO(ioError);}let mut source = String::new();if let Err(ioError) = file.read_to_string(&mut contents) {return ParseFileError::IO(ioError);}let expr = parse(&source[..]);if let Err(parseError) = expr {return ParseFileError::Syntax(parseError);}return expr.unwrap();
}

再來看有嚴格的 exception 會怎樣:

enum Token {/* 定義詞法分析的結果:token */
}enum Expr {/* 定義語法分析的結果:表達式 */
}/* 可以任意定義多種異常 */
#[derive(Exception)]
struct EOF;#[derive(Exception)]
struct UnexpectedEOF;#[derive(Exception)]
struct LexError(String);#[derive(Exception)]
struct SyntaxError(String);/* 返回類型變為單純的 Token,加上異常標注 */
fn next_token(source: &str) -> Tokenthrows EOF, UnexpectedEOF, LexError { /* ... */ }/* 返回類型變為單純的 Expr,并且只需處理有必要處理的 next_token 拋出的異常 */
fn parse(source: &str) -> Exprthrows EOF, UnexpectedEOF, SyntaxError {/* ... */let token = next_token(source) except {LexError(msg) => throw SyntaxError(msg),_ => throw _,}
}/* io::Error 除了要標注,可以完全不用管,清爽很多。再見了,unwrap! */
fn parseFile(path: &str) -> Exprthrows EOF, UnexpectedEOF, SyntaxError, io::Error {let mut file = std::fs::File::open(path)?;let mut source = String::new();file.read_to_string(&mut contents)?;let expr = parse(&source[..])?;return expr;
}

意義不言自明。

更新,感謝評論區 lanus 大佬(不知道為什么@不到)的啟發,補充兩點。

  1. 足夠強大的編譯器可以推斷 Exception,而不需要手動用 throws 標記。相反,用 nothrow 標記不希望拋異常的函數,在里面編譯器強制要求捕獲并處理所有異常。
  2. Result 即便要轉換,但開銷還是少于恢復 exception。我想了一下,解決方向有兩種,一種是仍然不要 Result,設法降低 exception 開銷;另一種是加入 Result,但不用標注,由編譯器推斷,保留兩種開銷不同的機制。后者看起來更完美,但編譯器要暗戳戳地改變返回類型。并且必須有匿名枚舉,就像 TypeScript 的那種純粹的 sum type。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/539498.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/539498.shtml
英文地址,請注明出處:http://en.pswp.cn/news/539498.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java @Transient 注解使用

2019獨角獸企業重金招聘Python工程師標準>>> 我們建實體類的時候啊&#xff0c;有時候實體類的屬性和數據庫表字段不一致的時候&#xff0c;比如多一個屬性&#xff0c;那你不加這個注解就會報錯&#xff0c;因為映射的時候會提示&#xff08;提示啥我給忘了&#x…

Myeclipse/eclipse 安裝查看class文件的插件

從http://www.oschina.net/project/tag/317/decompiler?lang19&os0&sortview 中下載了 也可到我的網盤&#xff1a;http://pan.baidu.com/s/1eS5BMcM 下載 Java反編譯工具jad &#xff08;jad.exe&#xff09;和 Java反編譯插件 Jadclipse &#xff08;net.sf.jadcl…

oracle—ebs_采購功能點操作手冊,oracle—EBS_采購功能點操作手冊

erp實施企業采購模塊構架及日常業務操作指導“人力資源”頁簽可以設置是否“使用審批層次結構”來決定采購單據的審批路徑。如不選定&#xff0c;則表示采購單據將使用員工的“主管”結構來進行審批。“員工編號”方法默認自業務組定義時的“員工編號生成”方法設置。1.2采購選…

Https的前世今生

1、年前會議 馬上要過年了&#xff0c;公司業務上的需求也少了很多&#xff0c;這不&#xff0c;王小二他們召開了一場技術會議&#xff0c;盤點年前能干點啥。 只見C哥寫了一份清單&#xff0c;其中一項是全站升級https。 C哥說&#xff1a;https是一種趨勢&#xff0c;但目前…

combobox控件 如何把三角形放大_初中數學|全等三角形全部知識點總結

今天&#xff0c;琦老師為大家整理了[初中數學重要考點&#xff0c;全等三角形的全部知識點]&#xff0c;希望幫助大家中考數學快速提分( #小學數學#初中數學#數學)除了圖片內容&#xff0c;大米君也為大家分享[如何靈活運用這些知識點的方法]大家記得跟著做起來哦~提高復習效果…

Spring中引入其他配置文件

原文&#xff1a;http://www.cnblogs.com/LiuChunfu/p/5605473.html ------------------------------------------------------------------------------ 一、引入其他 模塊XML   在Spring的配置文件&#xff0c;有時候為了分模塊的更加清晰的進行相關實體類的配置。 比如…

oracle不要重復記錄,Oracle中去重復記錄 不用distinct

用distinct關鍵字只能過濾查詢字段中所有記錄相同的(記錄集相同)&#xff0c;而如果要指定一個字段卻沒有效果&#xff0c;另外distinct關鍵字會排序&#xff0c;效率很低 。select distinct name from t1 能消除重復記錄&#xff0c;但只能取一個字段&#xff0c;現在要同時取…

miui游戲驅動程序偏好設置_米粉必看:小米官方教你如何關閉 MIUI 廣告 - 小米,MIUI...

IT之家 11 月 9 日消息 小米的 MIUI 在用戶心中的口碑一直是比較好的&#xff0c;但該系統也并非完美&#xff0c;被吐槽的較多的一個點就是系統內的廣告比較多。今天&#xff0c;小米官方微博 小米服務那些事 分享了幾個能夠減少 MIUI 廣告的方法&#xff0c;米粉不妨了解一下…

Spring Cloud Zuul網關 Filter、熔斷、重試、高可用的使用方式。

時間過的很快&#xff0c;寫springcloud(十)&#xff1a;服務網關zuul初級篇還在半年前&#xff0c;現在已經是2018年了&#xff0c;我們繼續探討Zuul更高級的使用方式。 上篇文章主要介紹了Zuul網關使用模式&#xff0c;以及自動轉發機制&#xff0c;但其實Zuul還有更多的應用…

oracle 9 插入日期,oracle date日期類型 精析

一、date1.date、sysdate格式說明展示date類型&#xff0c;展示格式既可以為&#xff1a;YYYY/MM/DD&#xff0c;也可以為YYYY/MM/DD HH24:MI:SS&#xff1b;其存儲格式只有一種&#xff1a;YYYY/MM/DD HH24:MI:SS展示格式一&#xff1a;當你只存年月日時&#xff0c;date實際存…

為什么使用NativeJdbcExtractor

原文&#xff1a;http://blog.csdn.net/hehexiaoyou/article/details/21019171---------------------------------------------------------------------------有時候必要會對數據庫clob、 blob數據型進行操作&#xff0c;再加上spring 環境不得不要啟用NativeJdbcExtractor 來…

CentOS 7.1下KVM的安裝與配置

由于沒有物理機可用&#xff0c;在自己的VMware Workation中CentOS 7搭建完成。 首先查看VMware Workation是否支持虛擬化&#xff0c;把紅框內打鉤即可。 虛擬化開啟并安裝CentOS系統&#xff0c;建議CentOS安裝64bit。我的環境用的是CentOS 7。進入系統&#xff0c;首先查看服…

軟件生成問候圖片_這些社交軟件你玩過幾個?

提到聊天軟件&#xff0c;我們的手機肯定安裝有微信QQ&#xff0c;不過微信QQ都是主打熟人社交&#xff0c;而下面幾個軟件都是陌生人社交。這些社交軟件&#xff0c;總有一款你安裝過。注意&#xff0c;非按排名介紹。第一款:陌陌陌陌是一款基于地理位置的開放式移動視頻社交應…

通過Sqoop實現Mysql / Oracle 與HDFS / Hbase互導數據

下文將重點說明通過Sqoop實現Mysql與HDFS互導數據&#xff0c;Mysql與Hbase,Oracle與Hbase的互導最后給出命令。一、Mysql與HDFS互導數據環境&#xff1a; 宿主機器操作系統為Win7&#xff0c;Mysql安裝在宿主機上&#xff0c;宿主機地址為192.168.66.963臺虛擬機操作系統為Ubu…

Android5.0新控件

谷歌在推出Android5.0的同時推出了一些新控件&#xff0c;Android5.0中最常用的新控件有下面5種。 1. CardView&#xff08;卡片視圖&#xff09; CardView顧名思義是卡片視圖&#xff0c;它繼承FrameLayout。它是一個帶圓角的背景和陰影FrameLayout。CardView被包裝為一種布局…

python中要使用導入全部的是什么符號-在python格式字符串中使用標點符號

這是因為您可以使用格式迷你語言來訪問對象的屬性.例如,我經常在自己的自定義類工作中使用它.假設我為每臺需要處理的計算機定義了一個類. class Computer(object): def __init__(self,IP): self.IP IP 而現在我想對整個計算機做一些事情 list_comps [Computer(name,"19…

oracle 讀懂10046視頻,10046、10053、實操記錄

10046是一個Oracle的內部事件(event)&#xff0c;通過設置這個事件可以得到Oracle內部執行系統解析、調用、等待、綁定變量等詳細的trace信息&#xff0c;即幫助我們解析一條/多條SQL、PL/SQL語句的運行狀態&#xff0c;這些狀態包括&#xff1a;Parse/Fetch/Execute三個階段中…

linux重定向文件被修改后,Linux服務器修改.htaccess文件實現301重定向

出于 SEO、PR 值傳遞、網址轉換的目的&#xff0c;在網站初建和網站遷移時我們都需要使用 301 重定向&#xff0c;通常包括域名對域名&#xff0c;目錄對目錄和一個獨立網址對另一個獨立網址的重定向。在虛擬主機上作 301 重定向&#xff0c;最常用的方法有2種&#xff1a;第一…

Druid使用起步—在javaWeb項目中配置監控

原文章&#xff1a;http://my.oschina.net/u/568779/blog/152813 ---------------------------------------------------- druid wiki 當我們在javaWEB項目中使用到druid來作為我們的連接池的時候&#xff0c;一定不會忘了添加監控功能。下面我們就來看一下&#xff0c;在一個…

[譯] 想幫助用戶做決定?你的APP可以這樣設計!

原文地址&#xff1a;Design your app for decision-making原文作者&#xff1a;Jeni譯文出自&#xff1a;掘金翻譯計劃本文永久鏈接&#xff1a;github.com/xitu/gold-m…譯者&#xff1a;PTHFLY校對者&#xff1a;ryouaki想幫助用戶做決定&#xff1f;你的APP可以這樣設計&am…