天天看點

【GoLang】panic defer recover 深入了解

唉,隻能說C程式員可以接受go的錯誤設計,相比java來說這個設計真的很差勁!

我認為知乎上說的比較中肯的:

【GoLang】panic defer recover 深入了解

1. The key lesson, however, is that errors are values and the full power of the Go programming language is available for processing them.

2. Use the language to simplify your error handling.

But remember: Whatever you do, always check your errors!

Golang這麼時尚的語言是沒有類似try..catch 這種異常處理機制,而是使用 panic 和 recover處理異常. 其實相當于python的raise。

golang的異常處理組合 panic,defer,recover,跟java中的try catch finially是類似的。 但是從語言的使用者體驗來說,不怎麼好。 但考慮到golang的場景基本是系統高性能層面的,這種精準錯誤處理應該減少那種後遺症bug。

該文章寫的有些亂,歡迎來噴 ! 另外文章後續不斷更新中,請到原文位址檢視更新。

http://xiaorui.cc/?p=2909

使用panic抛出異常,抛出異常後将立即停止目前函數的執行并運作所有被defer的函數,然後将panic抛向上一層,直至程式carsh。但是也可以使用被defer的recover函數來捕獲異常阻止程式的崩潰,recover隻有被defer後才是有意義的。

必須注意:

1.   defer 需要放在 panic 之前定義,另外recover隻有在 defer 調用的函數中才有效。

2.   recover處理異常後,邏輯并不會恢複到 panic 那個點去,函數跑到 defer 之後的那個點.

3.   多個 defer 會形成 defer 棧,後定義的 defer 語句會被最先調用

panic (主動爆出異常) 與 recover (收集異常)

recover 用來對panic的異常進行捕獲. panic 用于向上傳遞異常,執行順序是在 defer 之後。 

我們舉個含有異常的例子:

Python

1

2

3

4

5

6

7

8

9

10

11

12

#xiaorui.cc

func f() {

    for {

        fmt.Println("1")

        a := []string{"a","b"}

        fmt.Println(a[3])  // 這裡slice越界異常了

        /*panic("bug")*/

        fmt.Println("4")

        time.Sleep(1 * time.Second)

    }

}

如果你不把這個異常panic recover處理的化,那麼就會發生下面的情況.

13

panic: runtime error: index out of range

goroutine 1 [running]:

panic(0xda9c0, 0x8201c8090)

    /usr/local/go/src/runtime/panic.go:464 +0x3e6

main.f()

    /Users/ruifengyun/gg.go:23 +0x33b

main.main()

    /Users/ruifengyun/gg.go:16 +0x14

exit status 2

下面是處理panic的例子. 

14

15

16

17

18

19

20

21

22

23

24

25

26

27

package main

import (

    "fmt"

    "time"

)

func main() {

    defer func() { //必須要先聲明defer,否則不能捕獲到panic異常

        fmt.Println("2")

        if err := recover(); err != nil {

            fmt.Println(err) //這裡的err其實就是panic傳入的内容,bug

        }

        fmt.Println("3")

    }()

    f()

        panic("bug")

        fmt.Println("4") //不會運作的.

那麼上面代碼的運作結果是:

bug

上面go代碼執行個體中,異常是我們通過panic方法主動抛出來的,但如果真的就出現了未知的異常咋辦?

我們可以看到出現的異常會走到defer這一步,defer這裡可以列印具體的異常資訊,defer運作完之後不能回到原點,控制權會被扔到該函數的外層,也就是調用這個函數的層,對應上面的代碼也就是main()函數。

上面go代碼運作結果是:

xiaorui.cc start

runtime error: index out of range

xiaorui.cc end

end

先前沒在意defer  recover  panic的注意事項,結果各種問題出現了。 不知道go以後會不會有try catch異常模式, 很是期待… 

END.

參考資料:

http://xiaorui.cc/2016/03/09/%E5%85%B3%E4%BA%8Egolang%E7%9A%84panic-recover%E5%BC%82%E5%B8%B8%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86/

http://www.linuxidc.com/Linux/2013-04/83105.htm

http://blog.csdn.net/wuwenxiang91322/article/details/9042503

 https://www.zhihu.com/question/27158146