Golang 全面深入系列之 Error

Posted 51reboot运维开发

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang 全面深入系列之 Error相关的知识,希望对你有一定的参考价值。


What you are wasting today is tomorrow for those who died yesterday; what you hate now is the future you can not go back.


你所浪费的今天是昨天死去的人奢望的明天; 你所厌恶的现在是未来的你回不去的曾经。


Go errors 简介


Go 的惯用法中,返回值不是整型等常用返回值类型,而是用了一个 error( interface 类型)。


// 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 一样......错误值可以存储在变量中,从函数返回等等。


ackage 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.


在 go 中处理错误的惯用方式是将返回的错误与 nil 进行比较。零值表示没有发生错误,而非零值表示存在错误。在上面的例子中,我们检查错误是否不为 nil。如果不是,我们只需打印错误并从主函数返回。


错误类型定义


type error interface {  
   Error() string
}


我们知道,golang 中 error 的定义是一个接口类型, 任何实现此接口的类型都可以用作错误的输出调用。此方法提供错误的描述。当打印错误时,fmt.println 函数在内部调用 Error()字符串方法来获取错误的描述。


从错误中提取更多信息的不同方式


现在我们知道 error 是一种接口类型,可以让我们看看如何提取更多有关的错误信息。例如:上面例子中,我们想提取导致错误的文件路径该如何获取?


1.声明底层结构类型并从结构字段获取更多信息


如果仔细阅读 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 的一个实例。

现在,我们已成功使用类型断言来从错误中获取文件路径。


2.声明底层结构类型并使用方法获取更多信息


通过调用结构类型的方法来断言底层类型并获取更多信息。

让我们通过一个例子来更好地理解这一点。标准库中的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,  我们就可以确定错误既不是暂时性的,也不是由于超时。


3.直接比较


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 的错误类型。


最后一点:

永远不要忽略错误

记住!!!多写一点小麻烦,省掉千千万万个大麻烦!!!


最后,写的有点匆忙,有错误之处还望指正!


本文来自:开源中国博客

原文链接:http://t.cn/Rnf0Dq0

 

往期推荐阅读









Golang 全面深入系列之 Error

Golang 班、架构师班、自动化运维班正在招生中


各位小伙伴们,欢迎试听和咨询:


QQ(1):979950755    小月   


QQ(2):279312229    ada   


WeChat : 1902433859   小月


WeChat : 1251743084   小单


技术交流群:


Golang 技术交流群 426582602


Python 交流群 365534424 / 238757010


Golang 全面深入系列之 Error

详情点击【阅读原文】即可跳转

以上是关于Golang 全面深入系列之 Error的主要内容,如果未能解决你的问题,请参考以下文章

轻松精通数据库管理之道——运维巡检系列

GoLang之错误处理

.Net Discovery系列之三 深入理解.Net垃圾收集机制(上)

Golang系列之单元测试快速入门

手撸golang etcd raft协议之8

手撸golang etcd raft协议之4