本文目錄一覽:
- 1、golang編程中,不屬於異常處理的關鍵詞是
- 2、Golang 里的fatal error怎麼處理
- 3、golang 執行系統命令ps aux|grep “xxxx”,總是異常退出
- 4、go defer,panic,recover詳解 go 的異常處理
- 5、Golang 中更好的錯誤處理:理論和實踐技巧
golang編程中,不屬於異常處理的關鍵詞是
error。Go語言又稱Golang是Google開發的一種靜態強類型、編譯型、並髮型,並具有垃圾回收功能的編程語言,在該語言種類中error不屬於異常處理的關鍵詞,因為error僅僅是用來提示錯誤的詞,和異常處理功能無關。
Golang 里的fatal error怎麼處理
意思為:致命的錯誤。一般指內存讀取出錯
因素為內存不夠或故障另種是讀取文件失敗,文件是只讀文件。
一般有3種可能:
第1種是內存太小,可以加內存
第2種是某些文件屬性不改是只讀而設置成了只讀,把所有文件屬性的只讀去掉就行了(可以先整個文件夾所有文件設成只讀,再全部去掉只讀屬性比較快)
第2種再不然就是軟硬體有衝突了 。
golang 執行系統命令ps aux|grep “xxxx”,總是異常退出
你這個是兩個命令,不是一個命令。
grep是查找命令,你應該:
exec.Command(“ps”, “aux”).Output()
出結果後再過慮。
go defer,panic,recover詳解 go 的異常處理
golang中defer,panic,recover是很常用的三個特性,三者一起使用可以充當其他語言中try…catch…的角色,而defer本身又像其他語言的析構函數
結果:
例1
例2
例3
請先不要向下看,在心裡跑一遍上邊三個例子的結果,然後去驗證
可能你會認為: 例1的結果是0,例2的結果是10,例3的結果是6 ,那麼很遺憾的告訴你,這三個結果都錯了
為什麼呢,最重要的一點就是要明白, return xxx這一條語句並不是一條原子指令
含有defer函數的外層函數,返回的過程是這樣的:先給返回值賦值,然後調用defer函數,最後才是返回到更上一級調用函數中,可以用一個簡單的轉換規則將return xxx改寫成
例1可以改寫成這樣
所以例1的返回值是1
例2可以改寫成這樣
所以例2的結果是5
例3可以改寫成這樣
所以例3的結果是1
在defer函數申明時,對外部變數的引用是有兩種方式:作為函數參數和作為閉包引用
作為函數參數,在defer申明時就把值傳遞給defer,並將值緩存起來,調用defer的時候使用緩存的值進行計算(如上邊的例3)
而作為閉包引用,在defer函數執行時根據整個上下文確定當前的值
看個?
結果:
by smoke_zl
這裡有幾個需要注意的問題,通過?表現
在defer前panic
結果,b沒有被列印出來:
而在defer後panic
結果,b被正常列印:
結果:
結果:
結果:
結果:
編譯錯誤,結果:
結果:
參考:
https: //golang.org/pkg/builtin/#recover
https: //
Golang 中更好的錯誤處理:理論和實踐技巧
雲和安全管理服務專家新鈦雲服 張春翻譯
這種方法有幾個缺點。首先,它可以對程序員隱藏錯誤處理路徑,特別是在捕獲異常不是強制性的情況下,例如在 Python 中。即使在具有必須處理的 Java 風格的檢查異常的語言中,如果在與原始調用不同的級別上處理錯誤,也並不總是很明顯錯誤是從哪裡引發的。
我們都見過長長的代碼塊包裝在一個 try-catch 塊中。在這種情況下,catch 塊實際上充當 goto 語句,這通常被認為是有害的(奇怪的是,C 中的關鍵字被認為可以接受的少數用例之一是錯誤後清理,因為該語言沒有 Golang- 樣式延遲語句)。
如果你確實從源頭捕獲異常,你會得到一個不太優雅的 Go 錯誤模式版本。這可能會解決混淆代碼的問題,但會遇到另一個問題:性能。在諸如 Java 之類的語言中,拋出異常可能比函數的常規返回慢數百倍。
Java 中最大的性能成本是由列印異常的堆棧跟蹤造成的,這是昂貴的,因為運行的程序必須檢查編譯它的源代碼 。僅僅進入一個 try 塊也不是空閑的,因為需要保存 CPU 內存寄存器的先前狀態,因為它們可能需要在拋出異常的情況下恢復。
如果您將異常視為通常不會發生的異常情況,那麼異常的缺點並不重要。這可能是傳統的單體應用程序的情況,其中大部分代碼庫不必進行網路調用——一個操作格式良好的數據的函數不太可能遇到錯誤(除了錯誤的情況)。一旦您在代碼中添加 I/O,無錯誤代碼的夢想就會破滅:您可以忽略錯誤,但不能假裝它們不存在!
try {
doSometing()
} catch (IOException e) {
// ignore it
}
與大多數其他編程語言不同,Golang 接受錯誤是不可避免的。 如果在單體架構時代還不是這樣,那麼在今天的模塊化後端服務中,服務通常和外部 API 調用、資料庫讀取和寫入以及與其他服務通信 。
以上所有方法都可能失敗,解析或驗證從它們接收到的數據(通常在無模式 JSON 中)也可能失敗。Golang 使可以從這些調用返回的錯誤顯式化,與普通返回值的等級相同。從函數調用返回多個值的能力支持這一點,這在大多數語言中通常是不可能的。Golang 的錯誤處理系統不僅僅是一種語言怪癖,它是一種將錯誤視為替代返回值的完全不同的方式!
重複 if err != nil
對 Go 錯誤處理的一個常見批評是被迫重複以下代碼塊:
res, err := doSomething()
if err != nil {
// Handle error
}
對於新用戶來說,這可能會覺得沒用而且浪費行數:在其他語言中需要 3 行的函數很可能會增長到 12 行 :
這麼多行代碼!這麼低效!如果您認為上述內容不優雅或浪費代碼,您可能忽略了我們檢查代碼中的錯誤的全部原因:我們需要能夠以不同的方式處理它們!對 API 或資料庫的調用可能會被重試。
有時事件的順序很重要:調用外部 API 之前發生的錯誤可能不是什麼大問題(因為數據從未通過發送),而 API 調用和寫入本地資料庫之間的錯誤可能需要立即注意,因為 這可能意味著系統最終處於不一致的狀態。即使我們只想將錯誤傳播給調用者,我們也可能希望用失敗的解釋來包裝它們,或者為每個錯誤返回一個自定義錯誤類型。
並非所有錯誤都是相同的,並且向調用者返回適當的錯誤是 API 設計的重要部分,無論是對於內部包還是 REST API 。
不必擔心在你的代碼中重複 if err != nil ——這就是 Go 中的代碼應該看起來的樣子。
自定義錯誤類型和錯誤包裝
從導出的方法返回錯誤時,請考慮指定自定義錯誤類型,而不是單獨使用錯誤字元串。字元串在意外代碼中是可以的,但在導出的函數中,它們成為函數公共 API 的一部分。更改錯誤字元串將是一項重大更改——如果沒有明確的錯誤類型,需要檢查返回錯誤類型的單元測試將不得不依賴原始字元串值!事實上,基於字元串的錯誤也使得在私有方法中測試不同的錯誤案例變得困難,因此您也應該考慮在包中使用它們。回到錯誤與異常的爭論,返回錯誤也使代碼比拋出異常更容易測試,因為錯誤只是要檢查的返回值。不需要測試框架或在測試中捕獲異常 。
可以在 database/sql 包中找到簡單自定義錯誤類型的一個很好的示例。它定義了一個導出常量列表,表示包可以返回的錯誤類型,最著名的是 sql.ErrNoRows。雖然從 API 設計的角度來看,這種特定的錯誤類型有點問題(您可能會爭辯說 API 應該返回一個空結構而不是錯誤),但任何需要檢查空行的應用程序都可以導入該常量並在代碼中使用它不必擔心錯誤消息本身會改變和破壞代碼。
對於更複雜的錯誤處理,您可以通過實現返回錯誤字元串的 Error() 方法來定義自定義錯誤類型。自定義錯誤可以包括元數據,例如錯誤代碼或原始請求參數。如果您想表示錯誤類別,它們很有用。DigitalOcean 的本教程展示了如何使用自定義錯誤類型來表示可以重試的一類臨時錯誤。
通常,錯誤會通過將低級錯誤與更高級別的解釋包裝起來,從而在程序的調用堆棧中傳播。例如,資料庫錯誤可能會以下列格式記錄在 API 調用處理程序中:調用 CreateUser 端點時出錯:查詢資料庫時出錯:pq:檢測到死鎖。這很有用,因為它可以幫助我們跟蹤錯誤在系統中傳播的過程,向我們展示根本原因(資料庫事務引擎中的死鎖)以及它對更廣泛系統的影響(調用者無法創建新用戶)。
自 Go 1.13 以來,此模式具有特殊的語言支持,並帶有錯誤包裝。通過在創建字元串錯誤時使用 %w 動詞,可以使用 Unwrap() 方法訪問底層錯誤。除了比較錯誤相等性的函數 errors.Is() 和 errors.As() 外,程序還可以獲取包裝錯誤的原始類型或標識。這在某些情況下可能很有用,儘管我認為在確定如何處理所述錯誤時最好使用頂級錯誤的類型。
Panics
不要 panic()!長時間運行的應用程序應該優雅地處理錯誤而不是panic。即使在無法恢復的情況下(例如在啟動時驗證配置),最好記錄一個錯誤並優雅地退出。panic比錯誤消息更難診斷,並且可能會跳過被推遲的重要關閉代碼。
Logging
我還想簡要介紹一下日誌記錄,因為它是處理錯誤的關鍵部分。通常你能做的最好的事情就是記錄收到的錯誤並繼續下一個請求。
除非您正在構建簡單的命令行工具或個人項目,否則您的應用程序應該使用結構化的日誌庫,該庫可以為日誌添加時間戳,並提供對日誌級別的控制。最後一部分特別重要,因為它將允許您突出顯示應用程序記錄的所有錯誤和警告。通過幫助將它們與信息級日誌分開,這將為您節省無數時間。
微服務架構還應該在日誌行中包含服務的名稱以及機器實例的名稱。默認情況下記錄這些時,程序代碼不必擔心包含它們。您也可以在日誌的結構化部分中記錄其他欄位,例如收到的錯誤(如果您不想將其嵌入日誌消息本身)或有問題的請求或響應。只需確保您的日誌沒有泄露任何敏感數據,例如密碼、API 密鑰或用戶的個人數據!
對於日誌庫,我過去使用過 logrus 和 zerolog,但您也可以選擇其他結構化日誌庫。如果您想了解更多信息,互聯網上有許多關於如何使用這些的指南。如果您將應用程序部署到雲中,您可能需要日誌庫上的適配器來根據您的雲平台的日誌 API 格式化日誌 – 沒有它,雲平台可能無法檢測到日誌級別等某些功能。
如果您在應用程序中使用調試級別日誌(默認情況下通常不記錄),請確保您的應用程序可以輕鬆更改日誌級別,而無需更改代碼。更改日誌級別還可以暫時使信息級別甚至警告級別的日誌靜音,以防它們突然變得過於嘈雜並開始淹沒錯誤。您可以使用在啟動時檢查以設置日誌級別的環境變數來實現這一點。
原文:
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/287291.html