一、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.