Go的錯誤處理機制介紹 Defer, Panic與Recover

Posted by Kubeguts on 2018-05-13

Defer, Paic, Recover是Golang 用來做錯誤處理的常用函式

介紹

Panic

用來發出錯誤訊息,並中斷以下執行流程

Defer

可將某訊息或某執行方法推延後至程式結束,在執行。

Recover

只能在Defer中使用,用來接收panic傳入的參數,並做打印或其他執行。

範例

用以下例子來看 Panic、Recover與Defer的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import "fmt"

func main() {
f()
fmt.Println("Returned normally from f.")
}

func f() {
// 被推延至結束才執行,並且recover() 會接受panic所傳遞的參數
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
fmt.Println("Calling g.")
g(0)
fmt.Println("Returned normally from g.")
}

func g(i int) {
if i > 3 {
fmt.Println("Panicking!")
panic(fmt.Sprintf("%v", i))
}
// 將 印出“Defer in g"這段訊息 延後印出,直到panic觸發或是程式結束才會被印出來
// 先被defer的會最晚被印出來,為Last in first out !
defer fmt.Println("Defer in g", i)
fmt.Println("Printing in g", i)
g(i + 1)
}
1
2
3
4
5
6
7
8
9
10
11
12
Calling g.
Printing in g 0
Printing in g 1
Printing in g 2
Printing in g 3
Panicking!
Defer in g 3
Defer in g 2
Defer in g 1
Defer in g 0
Recovered in f 4
Returned normally from f.

補充

通常 defer 也會被用在 要關閉一個DB的instance

例如以下以mongoDB為例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
func someFunction() {
var err error

mongo, err := getMongoSession() // 回傳一個mongo的instance
mongo.SetSocketTimeout(1 * time.Hour)
//session.SetSocketTimeout(1 * time.Hour)

if err != nil {
errors := common.Error{
ErrorType: 1,
ErrorDescription: err.Error(),
}
logger.Console().Panic(errors)
logger.File().Error(err)
}

// 將關閉mongo的動作推延至 該function執行玩return後執行
defer mongo.Close()

collection := mongo.DB(dbName).C(collectionName.BsBlocks)
result := []blockStrcut.BlockWithOnlyTxHashesIntNum{}
err = collection.Find(conditions).All(&result)

return result, err
}

參考

The Go Blog:Defer, Panic, and Recover
https://blog.golang.org/defer-panic-and-recover