加入收藏 | 设为首页 | 会员中心 | 我要投稿 威海站长网 (https://www.0631zz.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 运营中心 > 建站资源 > 优化 > 正文

一文悟透备受争议的 Go 语言错误处理

发布时间:2019-09-20 00:56:34 所属栏目:优化 来源:佚名
导读:写过 C 的同学知道,C 语言中常常返回整数错误码(errno)来表示函数处理出错,通常用 -1 来表示错误,用 0 表示正确。 而在 Go 中,我们使用 error 类型来表示错误,不过它不再是一个整数类型,是一个接口类型: typeerrorinterface{ Error()string } 它表

当在外层调用 ReadFile 函数时:

  1. func main() { 
  2.     _, err := ReadConfig() 
  3.     if err != nil { 
  4.         fmt.Println(err) 
  5.         os.Exit(1) 
  6.     } 
  7. func ReadConfig() ([]byte, error) { 
  8.     home := os.Getenv("HOME") 
  9.     config, err := ReadFile(filepath.Join(home, ".settings.xml")) 
  10.     return config, errors.Wrap(err, "could not read config") 

这样我们在 main 函数里就能打印出这样一个错误信息:

  1. could not read config: open failed: open /Users/dfc/.settings.xml: no such file or directory 

它是有层次的,非常清晰。而如果我们用 pkg/errors 库提供的打印函数:

  1. func main() { 
  2.     _, err := ReadConfig() 
  3.     if err != nil { 
  4.         errors.Print(err) 
  5.         os.Exit(1) 
  6.     } 

能得到更有层次、更详细的错误:

  1. readfile.go:27: could not read config 
  2. readfile.go:14: open failed 
  3. open /Users/dfc/.settings.xml: no such file or directory 

上面讲的是 Wrap 函数,接下来看一下 “Cause” 函数,以前面提到的 temporary 接口为例:

  1. type temporary interface { 
  2.     Temporary() bool 
  3. // IsTemporary returns true if err is temporary. 
  4. func IsTemporary(err error) bool { 
  5.     te, ok := errors.Cause(err).(temporary) 
  6.     return ok && te.Temporary() 

判断之前先使用 Cause 取出错误,做断言,最后,递归地调用 Temporary 函数。如果错误没实现 temporary 接口,就会断言失败,返回 false。

Only handle errors once

什么叫“处理”错误:

  1. Handling an error means inspecting the error value, and making a decision. 

意思是查看了一下错误,并且做出一个决定。

例如,如果不做任何决定,相当于忽略了错误:

  1. func Write(w io.Writer, buf []byte) { w.Write(buf) 
  2.     w.Write(buf) 

w.Write(buf) 会返回两个结果,一个表示写成功的字节数,一个是 error,上面的例子中没有对这两个返回值做任何处理。

下面这个例子却又处理了两次错误:

  1. func Write(w io.Writer, buf []byte) error {  
  2.     _, err := w.Write(buf) 
  3.     if err != nil { 
  4.         // annotated error goes to log file 
  5.         log.Println("unable to write:", err) 
  6.      
  7.         // unannotated error returned to caller return err 
  8.         return err 
  9.     } 
  10.     return nil 

第一次处理是将错误写进了日志,第二次处理则是将错误返回给上层调用者。而调用者也可能将错误写进日志或是继续返回给上层。

这样一来,日志文件中会有很多重复的错误描述,并且在最上层调用者(如 main 函数)看来,它拿到的错误却还是最底层函数返回的 error,没有任何上下文信息。

(编辑:威海站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读