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