GoLang之錯誤處理

 

 

錯誤處理

 

error

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) } } }

 

 

 

defer 

你能夠在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()

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
}
相關文章
相關標籤/搜索