GO(4) - error and panic

Go 中錯誤跟異常為 error 和 panic。

error 是開發者可以預期的錯誤,而 panic 是較為嚴重未預期的錯誤。


1. error:

在 Go 中如果函式有機會發生 error 則該函式除了回傳計算結果外還需將錯誤一並回傳。

定義一個除法函式,回傳型別為 (float64, error)。如果 error 沒發生則將 error 設為 nil

package main

import (
    "errors"
    "fmt"
)

func divide(a float64, b float64) (float64, error) {
    if b != 0 {
        return a / b, nil
    }
    return 0, errors.New("b can't be 0")
}

func main() {
    a := 1.0
    b := 2.0
    if val, err := divide(a, b); err == nil {
        fmt.Printf("a/b=%f\n", val)
    }

    // b = 0
    // if _, err := divide(a, b); err != nil {
    //     fmt.Println(err)
    // }
}

2. panic:

panic 發生代表有某種開發者沒有預期的 bug。

func main() {
    n := 0
    res := 1 / n
    fmt.Println(res)
}

上面 res 會產生 panic: runtime error: integer divide by zero

有趣的是這個 panic 需要 integer 跟 divide by zero 兩件事同時滿足才會發生。

例如 n 是一個 float 時不會有 panic 產生,計算結果為 +Inf。

func main() {
    n := 0.0
    res := 1 / n
    fmt.Println(res)
}

3. recover:

panic 可以利用 recover 進行捕獲並處理。

利用 defer 註冊一個修復的機制。

func recoverPanic() {
    err := recover()
    fmt.Println("Panic: ", err)
}

func main() {
    defer recoverPanic()
    n := 0
    res := 1 / n
    fmt.Println(res)
}

當 res := 1 / n 造成 panic 時程式會脫離 main(),然後 recover() 會捕捉 panic。

由於 程式會脫離 main() 所以 fmt.Println(res) 不會被執行到。

另外要注意的是 defer 是延遲執行,所以 panic 未發生時會在 fmt.Println(res) 後被執行。

func main() {
    defer recoverPanic()
    n := 0.0
    res := 1 / n
    fmt.Println(res)
}

執行結果如下,沒有 panic 時 Println 會先被呼叫顯示 +Inf 再呼叫延遲的 recoverPanic()。

+Inf
Panic:  <nil>

留言

熱門文章