Go語言引入了一個錯誤處理的標準模式,即error接口,該接口定義以下:函數
type error interface {
Error() string
}
對於大多數函數,若是要返回錯誤,能夠將error做爲多返回值的最後一個:測試
func foo(param int)(ret int, err error)
{
...
}
調用時的代碼:spa
n, err := foo(0)
if err != nil { // 錯誤處理 } else { // 使用返回值n }
咱們還能夠自定義錯誤類型,一個例子:code
package main
import "fmt" import "errors" //自定義的出錯結構 type myError struct { arg int errMsg string } //實現Error接口 func (e *myError) Error() string { return fmt.Sprintf("%d - %s", e.arg, e.errMsg) } //兩種出錯 func error_test(arg int) (int, error) { if arg < 0 { return -1, errors.New("Bad Arguments - negtive!") }else if arg >256 { return -1, &myError{arg, "Bad Arguments - too large!"} } return arg*arg, nil } //相關的測試 func main() { for _, i := range []int{-1, 4, 1000} { if r, e := error_test(i); e != nil { fmt.Println("failed:", e) } else { fmt.Println("success:", r) } } }
你能夠在Go函數中添加多個defer語句,當函數執行到最後時,這些defer語句會按照逆序執行(即最後一個defer語句將最早執行),最後該函數返回。blog
特別是當你在進行一些打開資源的操做時,遇到錯誤須要提早返回,在返回前你須要關閉相應的資源,否則很容易形成資源泄露等問題。以下代碼所示,咱們通常寫打開一個資源是這樣操做的:接口
func CopyFile(dst, src string) (w int64, err error) {
srcFile, err := os.Open(src) if err != nil { return } defer srcFile.Close() dstFile, err := os.Create(dst) if err != nil { return } defer dstFile.Close() return io.Copy(dstFile, srcFile) }
若是defer後面一條語句幹不完清理工做,也可使用一個匿名函數:資源
defer func(){
...
}()
注意,defer語句是在return以後執行的,例如:原型
func test() (result int) {
defer func() {
result = 12 }() return 10 } func main() { fmt.Println(test()) // 12 }
panic()函數用於拋出異常,recover()函數用於捕獲異常,這兩個函數的原型以下:string
func panic(interface{})
func recover() interface{}
當在一個函數中調用panic()時,正常的函數執行流程將當即終止,但函數中以前使用defer關鍵字延遲執行的語句將正常展開執行,以後該函數將返回到調用函數,並致使逐層向上執行panic()流程,直至所屬的goroutine中全部正在執行的函數被終止。錯誤信息將被報告,包括在調用panic()函數時傳入的參數,這個過程稱爲錯誤流程處理。io
panic()接受一個interface{}參數,可支持任意類型,例如:
panic(404)
panic("network broken") panic(Error("file not exists"))
在defer語句中,可使用recover()終止錯誤處理流程,這樣能夠避免異常向上傳遞,但要注意recover()以後,程序不會再回到panic()那裏,函數仍在defer以後返回。
func foo() {
panic(errors.New("i'm a bug")) return } func test() (result int) { defer func() { if r := recover(); r != nil { err := r.(error) fmt.Println("Cache Exception:", err) } }() foo() return 10 } func main() { fmt.Println(test()) // 0 }
注意,在一個函數中panic被調用後,其defer語句仍會執行,
func foo()(n int) { defer func() { if r := recover(); r != nil { n++ // take effective } }() n++ // take effective panic(errors.New("i'm a bug")) n++ // take no effective return n }