Go異常處理


  一、error接口

    Go 語言通過內置的錯誤接口提供了非常簡單的錯誤處理機制

    error類型是一個接口,其定義如下:    

type error interface {
    Error() string }

    我們可以在代碼中通過實現error接口來生成錯誤信息。

    任意結構體,只要實現了 Error 方法,就可以認為是 error 錯誤類型。

    如,errors.New方法返回的就是一個實現了error接口的結構體實例,因為它是error類型:

func New(text string) error {
    return &errorString{text}
}

// errorString is a trivial implementation of error.
type errorString struct {
    s string
}

func (e *errorString) Error() string {
    return e.s
}

 

    Go提供了兩種創建error的方法:

      ①:errors.New

      ②:fmt.Errorf

    不過函數通常在最后的返回值中返回錯誤信息。使用errors.New 可返回一個錯誤信息:

import (
    "errors"
    "fmt"
)

func Hello(name string) (string, error) {
    // If no name was given, return an error with a message.
    if name == "" {
        // return "", fmt.Errorf("empty name")
        return "", errors.New("empty name")
    }

    // If a name was received, return a value that embeds the name
    message := fmt.Sprintf("Hi, %v. Welcome!", name)
    return message, nil
}

      我們會約定最后返回值為 error 類型,一般常見於第二個返回值,這是一個約定俗成的習慣。

    因此在調用返回error的方法的時候要注意判斷error是否為nil,如果不為nil,說明異常,要做異常處理:

import (
    "fmt"
    "log"
)

func main() {
    message, err := Hello("")
    // If an error was returned, print it to the console and
    // exit the program.
    if err != nil {
        log.Fatal(err)
    }

    // If no error was returned, print the returned message
    // to the console.
    fmt.Println(message)
}

 

 

   

  二、panic

    panic是一個Go內置函數,它用來停止當前常規控制流並啟動panicking(運行時恐慌)過程。

    panic的觸發有兩種:

      ①:在運行時遇到錯誤觸發 panic,比如越界訪問數組,不相同類型的變量強制類型轉換等

      ②:通過顯式直接調用 panic 函數觸發 panic

        func panic(v interface{}) panic  panic函數接收一個interface{}空接口類型的參數,也就是說,panic函數可以接收一個任意類型的參數。  

func test() {
    // 顯式調用panic
    panic("panic error!")
}

 

 

    怎么處理panic呢?

      異常的使用場景簡單描述:Go中可以拋出一個panic的異常,然后在defer中通過recover() 捕獲這個異常,將 panic 錯誤寫入日志文件,將程序恢復正常執行

      調用recover() 函數可以捕獲panic,即通過recover() 獲取panic。

      但是recover() 函數僅在defer函數內部使用。所以想要使用recover捕獲panic,我們需要結合defer一起使用。而且,程序在觸發panic異常后,不會繼續往下執行代碼,只能執行defer調用的函數。 

func a() int{
    i:=0
    return 10/i
}

func main() {
    // 捕獲處理panic
    defer func(){
        if r := recover(); r != nil {
            fmt.Printf("panic recover:%s", r)
        }
    }()
    // 觸發panic
    a()
    // 不會再執行
    fmt.Println("123")
}

      recover()是Go語言一個內置函數,可以重新獲取對一個運行時恐慌的 goroutine 的控制。recover 僅在 defer 延遲函數內部使用。在正常執行程序中,調用 recover 函數,將返回 nil。如果當前 goroutine 處於恐慌狀態,調用 recover 會捕獲提供給 panic 的值並恢復正常執行。

 

      通常,我們不會去捕獲運行時 panic,發生 panic 異常,直接讓程序崩潰即可,及時根據 panic 提供的信息,修復異常。但是,一些情況下,我們還是需要捕獲 panic,比如在程序發生 panic 異常時,釋放資源。比如關閉文件或者釋放鎖

    

    注意:

      在Go語言中,recover只在defer調用的函數中有效,並且defer要在panic之前先注冊,否則不能捕獲異常。當panic被捕獲到后,被注冊的函數將獲得程序控制權

    

    Go實現類似 try catch 的異常處理:

/*
實現類似try catch處理,后續代碼可正常執行
fun() 可能觸發panic的函數
hander() panic處理函數
*/
func Try(fun func(), handler func(interface{})) {
    defer func() {
        if err := recover(); err != nil {
            handler(err)
        }
    }()
    fun()
}

func main() {
    Try(func() {
        panic("test panic")
    }, func(err interface{}) {
        fmt.Println(err)
    })

    // 后續代碼可繼續執行
    fmt.Println("panic handled")
}

 

 

  error和panic區別:

    error一般是程序員可預知的,會進行合適的處理,例如檢測輸入是否合法等

    而panic是程序員無法預知的異常,例如空指針或數組越界等

 

  總結:panic 導致的后果非常嚴重,會導致程序崩潰,所以我們在處理一些不會影響程序正確運行的錯誤時,盡量使用 error 處理錯誤

 

 

  

  三、throw

    這個錯誤類型,在用戶側是沒法主動調用的,均為 Go 底層自行調用的,像是大家常見的 map 並發讀寫,就是由此觸發

     

 

END.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM