Golang 的異常處理

Golang的優點有很多,以前的文章中也有提到過,但也有很多槽點爲 Gopher 所詬病,尤其是 錯誤處理

在說錯誤和異常之前,先要說兩個概念:

錯誤處理:錯誤是業務中的一部分,是可以預見的。

異常處理:非業務的一部分,不可預見的。

錯誤處理

首先看一下示例代碼:

file, err := os.Open("/usr/local/test.txt")

Golang 官方推薦上述代碼中的錯誤處理方式,並且建議 err放在返回值的最後。我們在日常的編碼中也需要遵循這樣的規則來定義 func

在 Gopher 間流傳着這樣一個笑話:一半時間在編寫代碼,一半時間在寫錯誤處理。

示例代碼:

func Open(name string) (*File, error) {
   return OpenFile(name, O_RDONLY, 0)
}

但通常不是每個方法都需要處理 err,可以適當的將 err返回給上層函數,由上層函數統一打印或者處理錯誤。例如:http 路由中的錯誤可以在路由返回數據前處理,將錯誤信息和錯誤碼格式化後返回給 Client

異常處理

Golang 的異常處理比較特立獨行,需要 defer err recover()三者配合使用 ,而 Java 只要 try{}Catch()就可以搞定, 還是來看一下示例代碼:

package main
import (
    "fmt"
)
func main() {
    test()
}
func test()  {
    defer func() {
        if e := recover(); e != nil {
            fmt.Println("Worng!")
        }
    }()
    panic("panic")
}

如上代碼在 test()函數及其子函數中如果發生 panic 的錯誤,就會打印:

Worng!

代碼封裝

當然,在每個方法最上面寫這麼一大堆冗餘的代碼是很不優雅的,也不符合面向對象的特性:封裝,於是便可以封裝成 CoverErrorMessage() ,而 test()函數改寫如下:

package main
import (
    "fmt"
)
func main() {
    test()
}
func test()  {
    defer tools.CoverErrorMessage()
    panic("panic")
}
func  CoverErrorMessage() {
   if message := recover(); message != nil {
      var err error
      switch x := message.(type) {
      case string:
         err = errors.New(x)
      case error:
         err = x
      default:
         err = errors.New("Unknow panic")
      }
      Logger.Error("Recovered panic error : ",err)
   }
}

defer 處理異常時只能將 recover()寫在第一層函數中,否則將無法 recover()到 panic 錯誤

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/yxBha3DfFrIa9j9Ff4oTpg