加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

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

发布时间:2019-09-20 02:39:03 所属栏目:建站 来源:佚名
导读:写过 C 的同学知道,C 语言中常常返回整数错误码(errno)来表示函数处理出错,通常用 -1 来表示错误,用 0 表示正确。 而在 Go 中,我们使用 error 类型来表示错误,不过它不再是一个整数类型,是一个接口类型: typeerrorinterface{ Error()string } 它表
副标题[/!--empirenews.page--]

写过 C 的同学知道,C 语言中常常返回整数错误码(errno)来表示函数处理出错,通常用 -1 来表示错误,用 0 表示正确。

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

而在 Go 中,我们使用 error 类型来表示错误,不过它不再是一个整数类型,是一个接口类型:

  1. type error interface { 
  2.  Error() string 

它表示那些能用一个字符串就能说清的错误。

我们最常用的就是 errors.New() 函数,非常简单:

  1. // src/errors/errors.go 
  2. func New(text string) error { 
  3.     return &errorString{text} 
  4. type errorString struct { 
  5.     s string 
  6. func (e *errorString) Error() string { 
  7.     return e.s 

使用 New 函数创建出来的 error 类型实际上是 errors 包里未导出的 errorString 类型,它包含唯一的一个字段 s,并且实现了唯一的方法:Error() string。

通常这就够了,它能反映当时“出错了”,但是有些时候我们需要更加具体的信息,例如:

  1. func Sqrt(f float64) (float64, error) { 
  2.  if f < 0 { 
  3.  return 0, errors.New("math: square root of negative number") 
  4.  } 
  5.  // implementation 

当调用者发现出错的时候,只知道传入了一个负数进来,并不清楚到底传的是什么值。在 Go 里:

  1. It is the error implementation’s responsibility to summarize the context. 

它要求返回这个错误的函数要给出具体的“上下文”信息,也就是说,在 Sqrt 函数里,要给出这个负数到底是什么。

所以,如果发现 f 小于 0,应该这样返回错误:

  1. if f < 0 { 
  2.  return 0, fmt.Errorf("math: square root of negative number %g", f) 

这就用到了 fmt.Errorf 函数,它先将字符串格式化,再调用 errors.New 函数来创建错误。

当我们想知道错误类型,并且打印错误的时候,直接打印 error:

  1. fmt.Println(err) 

或者:

  1. fmt.Println(err.Error) 

fmt 包会自动调用 err.Error() 函数来打印字符串。

通常,我们将 error 放到函数返回值的最后一个,没什么好说的,大家都这样做,约定俗成。

参考资料【Tony Bai】这篇文章提到,构造 error 的时候,要求传入的字符串首字母小写,结尾不带标点符号,这是因为我们经常会这样使用返回的 error:

  1. ... err := errors.New("error example") 
  2. fmt.Printf("The returned error is %s.n", err) 

error 的困局

  1. In Go, error handling is important. The language’s design and conventions encourage you to explicitly check for errors where they occur (as distinct from the convention in other languages of throwing exceptions and sometimes catching them). 

在 Go 语言中,错误处理是非常重要的。它从语言层面要求我们需要明确地处理遇到的错误。而不是像其他语言,类如 Java,使用 try-catch- finally 这种“把戏”。

这就造成代码里 “error” 满天飞,显得非常冗长拖沓。

而为了代码健壮性考虑,对于函数返回的每一个错误,我们都不能忽略它。因为出错的同时,很可能会返回一个 nil 类型的对象。如果不对错误进行判断,那下一行对 nil 对象的操作百分之百会引发一个 panic。

这样,Go 语言中诟病最多的就是它的错误处理方式似乎回到了上古 C 语言时代。

  1. rr := doStuff1() 
  2. if err != nil { 
  3.  //handle error... 
  4. err = doStuff2() 
  5. if err != nil { 
  6.  //handle error... 
  7. err = doStuff3() 
  8. if err != nil { 
  9.  //handle error... 

Go authors 之一的 Russ Cox 对于这种观点进行过驳斥:当初选择返回值这种错误处理机制而不是 try-catch,主要是考虑前者适用于大型软件,后者更适合小程序。

在参考资料【Go FAQ】里也提到,try-catch 会让代码变得非常混乱,程序员会倾向将一些常见的错误,例如,failing to open a file,也抛到异常里,这会让错误处理更加冗长繁琐且易出错。

而 Go 语言的多返回值使得返回错误异常简单。对于真正的异常,Go 提供 panic-recover 机制,也使得代码看起来非常简洁。

当然 Russ Cox 也承认 Go 的错误处理机制对于开发人员的确有一定的心智负担。

(编辑:核心网)

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

热点阅读