1. 程式人生 > 其它 >go語言異常處理 error panic recover defer

go語言異常處理 error panic recover defer

error panic defer

python中可以用 try except來接收處理異常
go語言沒有這些
go的錯誤分為兩種,一種是人工手動丟擲的錯誤error, 一種是程式執行出錯的異常panic

defer

func DoDefer(){
    fmt.Println("在defer之前執行")
    defer fmt.Println("第一個defer")
    defer func() {
        fmt.Println("第二個defer")
    }()
    fmt.Println("我在defer中間,我也執行了")
    defer fmt.Println("第三個defer")
    fmt.Println("函式最後的語句執行了")
}

func main() {
    DoDefer()
}

執行結果:

在defer之前執行
我在defer中間,我也執行了
函式最後的語句執行了
第三個defer
第二個defer
第一個defer

結論:
defer執行時間: 函式其他語句執行完之後
defer執行順序: 堆疊順序,從下往上
所以說函式中除defer語句之外的程式碼執行完之後,函式執行完畢,函式指令的堆疊觸底上彈,此時開始從下往上執行註冊的defer
defer翻譯的意思是推遲,可以理解為是一個執行鉤子,並且只在函式執行觸底後出棧時才會執行(報錯,panic也會導致函式提前出棧)

panic

panic是嚴重異常,如果不進行捕獲的話,會導致程式退出
可以通過recover進行捕獲,需要配合defer關鍵字

func panicErr(info string) {
    panic("Panic Error " + info)
}

func MustError() {
    defer func() {
        err := recover()
        fmt.Println("Yes, Cover error", err)
    }()
    fmt.Println("異常之前,即將觸發異常")
    panicErr("After")
    fmt.Println("異常之後,異常函式內的程式碼仍然執行了")
}

func main() {
    MustError()
    fmt.Println("異常發生後,異常函式之外的程式碼仍然執行了")
}

執行結果:

異常之前,即將觸發異常
Yes, Cover error Panic Error After
異常發生後,異常函式之外的程式碼仍然執行了

可以看到,在執行出錯的函式之前通過defer註冊出棧的函式,當註冊之後的函式丟擲panic後,會進行正常捕獲,捕獲的函式MustError內,程式碼執行按照通常異常處理的方式中斷,並且出棧,該函數出錯語句之後的程式碼不再執行
函式的呼叫者函式依然可以正常執行

這和try except / try catch不通,try語法處理完try程式碼塊內的程式碼,不影響函式try外的程式碼執行
但是defer recover 不行,只要報錯,整個函式立即終止

再看另個形式:

func panicErr(info string) {
    panic("Panic Error " + info)
}

func MustError() {
    panicErr("Before")
    defer func() {
        err := recover()
        fmt.Println("Yes, Cover error", err)
    }()
    fmt.Println("異常之前,即將觸發異常")
    panicErr("After")
    fmt.Println("異常之後,異常函式內的程式碼仍然執行了")
}

func main() {
    MustError()
    fmt.Println("異常發生後,異常函式之外的程式碼仍然執行了")
}

和上面不同的是,在defer註冊出棧函式之前,先執行了一次丟擲錯誤的函式,結果就是defer語句無效了
因為程式碼入棧仍然是從上往下,還沒到註冊defer,就已經報錯了,所以出棧的時候defer的recover還沒註冊,自然執行不到了

所以,defer語句,最好在函式最開始就定義!!!

error

error在go裡面是error介面的例項,不是異常,更像是一個專用於錯誤資訊的類
函式通過return的方式來丟擲異常,不會像panic或者Python Exception 那樣不斷往上丟擲直到被捕獲,如果不接收,程式碼編譯會出錯,如果不想處理,可以用 _ 來接收,接收後不進行處理也不會出錯, 但是可能會造成程式設計人員對程式執行的期望出現偏差。

error的丟擲:

func returnErr(returnError bool) (int, error) {
    if returnError {
        return 1 ,errors.New("Some Error")
    }else {
        return 0, nil
    }
}

error更像是一種報警資訊,告訴程式設計師函式調用出現了意料之外的情況,需要注意,或者做相應處理
error不像panic那樣強制性的必須處理。