What you are wasting today is tomorrow for those who died yesterday; what you hate now is the future you can not go back.golang
你所浪費的今天是昨天死去的人奢望的明天; 你所厭惡的如今是將來的你回不去的曾經。app
Go 的慣用法中,返回值不是整型等經常使用返回值類型,而是用了一個 error( interface 類型)。ide
// The error built-in interface type is the conventional interface for // representing an error condition, with the nil value representing no error. type error interface { Error() string }
就像任何其餘內置類型,如 int,float64 同樣......錯誤值能夠存儲在變量中,從函數返回等等。函數
package main import ( "fmt" "os" ) func main() { f, err := os.Open("/test.txt") if err != nil { fmt.Println(err) return } fmt.Println(f.Name(), "opened successfully") }
若是文件 test.txt 不存在, Open 方法會返回 error.ui
在 go 中處理錯誤的慣用方式是將返回的錯誤與 nil 進行比較。零值表示沒有發生錯誤,而非零值表示存在錯誤。在上面的例子中,咱們檢查錯誤是否不爲 nil。若是不是,咱們只需打印錯誤並從主函數返回。code
type error interface { Error() string }
咱們知道,golang 中 error 的定義是一個接口類型, 任何實現此接口的類型均可以用做錯誤的輸出調用。此方法提供錯誤的描述。當打印錯誤時,fmt.println 函數在內部調用 Error()字符串方法來獲取錯誤的描述。接口
如今咱們知道 error 是一種接口類型,可讓咱們看看如何提取更多有關的錯誤信息。例如:上面例子中,咱們想提取致使錯誤的文件路徑該如何獲取?ci
若是仔細閱讀 open 函數的文檔,能夠看到它返回了類型 *Patherror 的錯誤。Patherror 是一個結構類型文檔
Open方法的實現:字符串
func Open(name string) (*File, error) { return OpenFile(name, O_RDONLY, 0) }
OpenFile方法的實現:
// OpenFile is the generalized open call; most users will use Open // or Create instead. It opens the named file with specified flag // (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful, // methods on the returned File can be used for I/O. // If there is an error, it will be of type *PathError. func OpenFile(name string, flag int, perm FileMode) (*File, error) { if name == "" { return nil, &PathError{"open", name, syscall.ENOENT} } r, errf := openFile(name, flag, perm) if errf == nil { return r, nil } r, errd := openDir(name) if errd == nil { if flag&O_WRONLY != 0 || flag&O_RDWR != 0 { r.Close() return nil, &PathError{"open", name, syscall.EISDIR} } return r, nil } return nil, &PathError{"open", name, errf} }
其中發生錯誤都返回了*PathError這個結構體實例。那麼咱們來看看這個結構體的具體信息。
// PathError records an error and the operation and file path that caused it. type PathError struct { Op string Path string Err error } func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }
此結構體實現了error接口。 結構體元素中也包括了 Path 的相關信息。
那麼咱們修改一上示例的代碼:
package main import ( "fmt" "os" ) func main() { f, err := os.Open("/test.txt") if errObject, ok := err.(*os.PathError); ok { fmt.Println("錯誤輸出:",err, "文件路徑:", errObject.Path) return } fmt.Println(f.Name(), "opened successfully") }
此時的 errObject 就是 PathError 的一個實例。
如今,咱們已成功使用類型斷言來從錯誤中獲取文件路徑。
經過調用結構類型的方法來斷言底層類型並獲取更多信息。
讓咱們經過一個例子來更好地理解這一點。標準庫中的DNSError結構類型定義以下:
type DNSError struct { ... } func (e *DNSError) Error() string { ... } func (e *DNSError) Timeout() bool { ... } func (e *DNSError) Temporary() bool { ... }
從上面的代碼能夠看出,DNSError 結構有兩個方法 timeout()bool 和 temporary()bool,它們返回一個布爾值,表示錯誤是因爲超時仍是臨時性的。
package main import ( "fmt" "net" ) func main() { addr, err := net.LookupHost("wwwwwwwwww.xxxx") if err, ok := err.(*net.DNSError); ok { if err.Timeout() { fmt.Println("operation timed out") } else if err.Temporary() { fmt.Println("temporary error") } else { fmt.Println("generic error: ", err) } return } fmt.Println(addr) }
程序會輸出:generic error: lookup wwwwwwwwww.xxxx: no such host, 咱們就能夠肯定錯誤既不是暫時性的,也不是因爲超時。
package main import ( "fmt" "path/filepath" ) func main() { files, error := filepath.Glob("[") if error != nil && error == filepath.ErrBadPattern { fmt.Println(error) return } fmt.Println("matched files", files) }
若是 Glob() 的模式錯誤,就會報 ErrBadPattern 的錯誤類型。
最後一點:
記住!!!多寫一點小麻煩,省掉千千萬萬個×××煩!!!
最後,寫的有點匆忙,有錯誤之處還望指正!
本文來自:開源中國博客
感謝做者:90design