Golang的異常處理
image
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 mainimport ( "fmt")func main() { test()}func test() { defer func() { if e := recover(); e != nil { fmt.Println("Worng!") } }() panic("panic")}
如上代碼在test()
函數及其子函數中如果發生panic的錯誤,就會列印:
Worng!
代碼封裝
當然,在每個方法最上面寫這麼一大堆冗餘的代碼是很不優雅的,也不符合物件導向的特性:封裝
,於是便可以封裝成CoverErrorMessage()
,而test()
函數改寫如下:
package mainimport ( "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錯誤
image