iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 19
1
Software Development

啥物碗Golang? 30天就Go系列 第 19

Error Handling 錯誤處理

  • 分享至 

  • twitterImage
  •  

俗話說得好:「神仙打鼓有時錯」,程式在執行階段當然難免會有錯誤產生。為了避免錯誤造成怎麼系統中斷或資料疑遺漏等嚴重的情況發生,合適的錯誤處理是不管哪種語言都需要考量的系統設計的一環,golang當然也不例外。golang不像是Java或是C#一樣有try...catch異常處理機制,而是靠著函數返回值逐層上回拋。比方說我們在第十天-靜態檔案分享伺服器中的例子:

if err := http.ListenAndServe(":8000", nil); err != nil {
    panic(err)
}

我們可以看到,藉由宣告一個變數err來接住錯誤狀態,透過判斷err != nil來做錯誤處理,在這個例子當中是將錯誤訊息列印下來。我們來看另外一個例子:

package main

import "fmt"

func main() {
	defer func() {
		fmt.Println("first")
		if err := recover(); err != nil {
			fmt.Println(err)
		}
		fmt.Println("end")
	}()
	f()
}

func f() {
	fmt.Println("test")
	panic(1)
	fmt.Println("test2")
}

defer會將程式放到一個暫存區塊,當函數要返回時才會執行,我們可以先想像為一個在函數回傳之前才會檢查待辦清單。panic在這邊會產生一個錯誤,錯誤訊息為1。所以上述的例子執行後,我們會得到:

test
first
1
end

這邊要特別注意的是test2是不會執行到的,因為錯誤的關係,程式執行到end就結束了。如果panic是真正的錯誤,go程式會因此而關閉,除非有使用recover回復他的數值。

Defer

關於defer有三大特性,這邊既然講到了就介紹一下,首先是「先進後出」,我們來看個簡單的例子:

package main

import "fmt"

func main() {
  for i := 0; i < 5; i++ {
    defer fmt.Println(i)
  }
}

如果沒有defer,很直覺地認為結果會是:

0
1
2
3
4

但因為defer先進後出的特性,我們得到的會是:

4
3
2
1
0

第二個特性是可以修改函數中的命名返回值,這樣講可能很難理解,我們直接看例子:

func c() (i int) {
    defer func() { i++ }()
    return 1
}

不考慮defer的話,返回值為1,但是因為defer會在返回時執行的特性,所以最終返回結果會是2而不是1。

第三點是defer中的變量在宣告的時候就已經被確立了,不會受到宣告以後的影響,一樣來看個例子:

func a() {
    i := 0
    defer fmt.Println(i)
    i++
    return
}

因為宣告的時候i = 0,所以結果就會印出0,而不是defer宣夠以後因為i++所以等於2。透過三個特性,有沒有更了解一點了呢?

回到錯誤處理當中,除了預先定義的錯誤訊息以外,我們當然也可以自定義錯誤訊息:

package main
 
import (
    "fmt"
)

type MyError struct {
    Title   string
    Message string
}
 
func (e MyError) Error() string {
    return fmt.Sprintf("%v: %v", e.Title, e.Message)
}
 
func main() {
    err := MyError{"Error Title 1", "Error Message 1"}
    fmt.Println(err)
 
    err = MyError{
        Title:   "Error Title 2",
        Message: "Error Message 2",
    }
    fmt.Println(err)
}

如何與程式中的錯誤相處,也是工程師很重要的一個修煉呢!

Reference


上一篇
Goroutine
下一篇
Testing 測試
系列文
啥物碗Golang? 30天就Go30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言