為什麼 Go 的錯誤處理很棒?

發布時間:2023-09-06 閱讀:2590

Go 臭名昭著的錯誤處理[1] 吸引了外界對程式語言的大量關注,它經常被認為是該語言最具爭議的設計決策之一。 如果你看一下 GitHub 上用 Go 編寫的任何專案,你幾乎可以保證你會看到最常見的**是:

if err !=nil 儘管對於那些剛接觸該語言的人來說,這似乎是多餘和不必要的,但go語言中的bug被認為是一等公民(價值觀)的原因在程式語言理論中有著悠久的歷史。 雖然已經做出了許多努力來改變或改進go處理錯誤的方式,但到目前為止,有乙個提案似乎比其他所有提案都好:

le**e if err !=nil alone![2]

圍棋的錯誤哲學。

Go 關於錯誤處理的哲學使開發人員將錯誤合併到他們編寫的大多數函式的一等公民中。 即使您使用類似於以下內容的內容,也要忽略該錯誤:

func getuserfromdb() user, error) func main() 大多數 linters 或 IDE 會發現您忽略了乙個錯誤,在審核過程中,您的團隊成員肯定會看到該錯誤。但是,在其他語言中,可能不清楚您沒有在 try catch 塊中處理潛在的異常,因為它在處理控制流時完全不透明。

如果以標準方式處理 Go 中的錯誤,您將獲得以下好處:

沒有隱藏的控制流沒有意外的未捕獲異常日誌炸毀您的終端(除了由於恐慌而導致的實際程式崩潰)可以完全控制**中的錯誤,可以選擇處理,返回並執行任何其他操作 func f() 值,error) 語法不僅易於向新手解釋,而且確保任何 Go 專案的一致性。

請務必注意,go 的錯誤語法不會強制您處理處理程式可能引發的每個錯誤。 Go 只是提供了一種模式,以確保您認為錯誤對程式流程至關重要,並且沒有進一步的要求。 在程式結束時,如果發生錯誤,請使用 err !=nil 來發現它,如果你的應用程式沒有對它做任何事情,你可能會遇到麻煩 - Go 不會自動為你儲存任何東西。 讓我們看乙個例子:

if err :=criticaldatabaseoperation();err !=nil if err :=s**euser(user); err !=nil 如果在呼叫 criticaldatabaseoperation() 時發生錯誤,即 err !=nil,那麼如果我們除了記錄錯誤之外不做任何事情,我們可能會遇到資料損壞或其他無法智慧型處理的不可預見的問題,解決方案是重試函式呼叫,或取消進一步的程式流,或者在最壞的情況下,退出程式。 圍棋不是乙個神奇的東西,它不會把你從這些情況中拯救出來。 Go 只提供了一種標準的方式來返回和使用錯誤作為值,但你仍然需要自己弄清楚如何處理錯誤。

其他語言如何做到這一點:丟擲異常。

在類似J**ascript節點的東西中在 JS 執行時的上下文中,可以通過以下方式構造程式,稱為引發異常:

嘗試捕獲 (e) 如果這些函式中的任何乙個發生錯誤,則會在執行時彈出錯誤的堆疊跟蹤並記錄到控制台,但沒有對所發生的問題進行顯式程式設計處理。

關鍵操作函式不需要顯式處理錯誤流,因為該 try 塊中發生的任何異常都會在執行時引發,並帶有錯誤原因的堆疊跟蹤。 與 go 相比,基於異常的語言的乙個好處是,即使在執行時發生未經處理的異常,它仍然通過堆疊進行跟蹤。 在 Go 中,更糟糕的是,可能根本無法處理嚴重錯誤。 Go 讓你完全控制錯誤處理,但也讓你負全部責任。

注意:異常絕對不是其他語言處理錯誤的唯一方式。 例如,Rust 在使用選項型別和模式匹配來查詢錯誤條件與利用一些不錯的語法糖來實現類似的結果之間做了很好的折衷。

為什麼go不使用異常進行錯誤處理。

去沒有禪。

《去之禪》提到了兩句重要的諺語:

簡單性對於失敗計畫很重要,而不是成功,並且對所有返回(值,錯誤)的函式使用簡單的if errs! = nil 片段有助於確保首先考慮程式失敗。 您無需為複雜的巢狀 try catch 塊而煩惱,它們會適當地處理所有可能的異常。

基於異常的 ** 通常是不透明的。

但是,對於基於異常的方案,你將意識到實際上存在異常,但它們未正確處理,因為它們被 try catch 塊捕獲。 也就是說,它鼓勵程式設計師永遠不要檢查錯誤,至少知道某些異常如果發生,將在執行時自動處理。

用基於異常的程式語言編寫的函式通常如下所示:

item = getfromdb()item.value = 400s**etodb(item)item.text = price changed'這無法確保正確處理異常。 也許上述**感知異常之間的區別是替換s**etodb(item)和itemtext = price changed'其順序是不透明的,難以推理,並且可能會鼓勵一些懶惰的程式設計習慣。 在函式式程式設計術語中,這被稱為幻想術語:違反引用透明度[3]。 Microsoft 2005 年工程部落格文章中的這一章 [4] 今天仍然適用,即:

我並不是說這個例外是不好的。 我的觀點是,異常太難了,我不夠聰明,無法處理它們。

go 錯誤語法的好處。

輕鬆建立可操作的錯誤鏈。

if err !=nil 模式的優點是錯誤鏈可以輕鬆地遍歷程式層次結構到發生錯誤的位置。 例如,由程式的 main 函式處理的常見 go 錯誤可能如下所示:

2020-07-05-9:00] 錯誤:無法建立 使用者:無法檢查使用者是否已存在於 DB:無法建立資料庫連線:沒有網際網絡 上述錯誤是 (a) 清除,(b) 可操作,(c) 有足夠的資訊來說明應用程式的哪一層出錯了。像這樣的錯誤不是由難以理解的堆疊跟蹤引起的,我們可以新增人類可讀的上下文來描述這些錯誤的原因,並且它們通過清晰的錯誤鏈進行處理,如上所示。

這一系列錯誤自然而然地成為標準 Go 程式結構的一部分,可能如下所示:

in controllers/user.goif err :=db.createuser(user); err !=nil //in database/user.gofunc (db *database) createuser(user *user) error .func (db *database) doesuserexist(user *user) error .func (db *database) connected() error .上述**的美妙之處在於,這些錯誤中的每乙個都完全由其自己的功能命名,該函式資訊豐富,僅對它們所知道的內容負責。 使用 FMTerrorf("something went wrong: %w",err) 使得構建很棒的錯誤訊息變得微不足道,這些錯誤訊息根據您的定義準確地告訴您出了什麼問題。

最重要的是,如果您還希望將堆疊跟蹤附加到您的函式中,則可以利用出色的 githubCOM pkg 錯誤庫,它為您提供以下功能:

errors.wrapf(err, "could not s**e user with email %s"、電子郵件)它將列印出堆疊跟蹤以及由 ** 建立的易於理解的錯誤鏈。如果可以的話,我想總結一下在 Go 中編寫符合 Go 的錯誤處理時想到的最重要的建議:

當您的錯誤需要服務開發人員時,新增堆疊跟蹤來處理返回的錯誤,不要只是彈出(返回),記錄它們,然後忘記它們以保持錯誤鏈清晰 當我編寫go**時,錯誤處理是我永遠不會擔心的一件事,因為錯誤本身是我編寫的每個函式的核心內容之一, 讓我完全控制如何安全、可讀和負責任地處理它們。

原始鏈結:作者:勞爾喬丹,由北極星參考編譯。

臭名昭著的錯誤處理:

le**e if err !=nil alone!:

違反引文透明度:

這篇博文:

為什麼女人婚後會改變,是生活迫於不得,還是錯誤的開始

我身邊乙個真實的故事。小茹是乙個經歷了七年婚姻之癢的溫柔女人,她自己也變成了乙個討厭自己的女人。這無疑是乙個悲慘的故事。我不想誇大其詞。只是因為她婚姻的不幸,我感慨萬千。小茹出生在舒香門底,父親是大學老師,母親是電視策劃人。小茹從小就熟悉人。在她的字典裡,每個人都是善良的,也許是被父親感染了,而在她...

為什麼我付出了我所擁有的一切,對方還是不理解?

很多女孩會說,我為他做了那麼多改變,那麼多讓步,但他會回頭嗎?為什麼我放下姿態,說出所有救贖的話,就留不住他?姑娘們,這裡用的都是 我為他.你有沒有想過,起點已經錯了,剩下的路一定是錯的,就像王菲在 給自己的情書 裡唱的 我不愛自己,怎麼能相愛 一樣。我的大學同學小文是出了名的 賢妻好媽媽 她白天工...

為什麼我們聽到的故事中有這麼多根本性錯誤

為什麼一夜之間一切都恢復了原來的樣子,只是早上鞋子沒有換回來?童話 灰姑娘 裡的這個問題,不是我們中國孩子提出的問題。為什麼這麼明顯的錯誤不被質疑,是中國孩子不夠聰明還是不夠好,無法發現細節?在一幅插圖中,一名學生質疑他的著裝,認為他所穿衣服的禮儀符合死者的著裝要求。這足以說明兩者之間沒有相關性。在...

華晨寶馬和寶馬有什麼區別? 為什麼處理方式如此不同?

華晨寶馬和寶馬有什麼區別?為什麼處理方式如此不同?說到寶馬汽車,我們總是習慣性地說 寶馬 其實國內有兩家公司與寶馬汽車有關。首先是寶馬集團與華晨汽車共同成立的 華晨寶馬 負責寶馬汽車在中國的生產和銷售。寶馬 中國 主要負責將寶馬汽車引入中國。也就是說,華晨寶馬出口的寶馬汽車是合資車,寶馬 中國 出口...

為什麼那麼多粉絲質疑居里,抓住他的錯誤,放大他?

作為一名改變了籃球風格的球員,他的顏值受到了很多NBA明星的質疑,所以無論居里表現得多麼好,還是有人質疑他的打法,當居里犯錯或者表現不佳時,他們會抓住這些錯誤並放大。他們為什麼要這樣做?乙個原因是居里不同於傳統的巨星。像喬丹 科比這樣的傳統巨星,一直依靠他們出色的個人和團隊領導能力幫助球隊取勝,關鍵...