這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
錯誤處理
error
Go語言引入了一個錯誤處理的標準模式,即error介面,該介面定義如下:
type error interface { Error() string}
對於大多數函數,如果要返回錯誤,可以將error作為多傳回值的最後一個:
func foo(param int)(ret int, err error){ ... }
調用時的代碼:
n, err := foo(0)if err != nil { // 錯誤處理} else { // 使用傳回值n}
我們還可以自訂錯誤類型,一個例子:
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語句將最先執行),最後該函數返回。
特別是當你在進行一些開啟資源的操作時,遇到錯誤需要提前返回,在返回前你需要關閉相應的資源,不然很容易造成資源流失等問題。如下代碼所示,我們一般寫開啟一個資源是這樣操作的:
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()函數用於捕獲異常,這兩個函數的原型如下:
func panic(interface{})func recover() interface{}
當在一個函數中調用panic()時,正常的函數執行流程將立即終止,但函數中之前使用defer關鍵字順延強制的語句將正常展開執行,之後該函數將返回到調用函數,並導致逐層向上執行panic()流程,直至所屬的goroutine中所有正在執行的函數被終止。錯誤資訊將被報告,包括在調用panic()函數時傳入的參數,這個過程稱為錯誤流程處理。
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}