Golang 错误处理:提供对用户友好的错误对象

本贴最后更新于 361 天前,其中的信息可能已经渤澥桑田

Golang 程序中,函数执行出错的标准做法是返回一个实现了 error​ 接口的对象。函数调用者遇到返回值中的 error​ 对象非空时,大部分情况下会直接将这个对象返回给上一级的调用者。即使在最外层的 main​ 函数,也可以抛一个 panic​ 把问题甩给用户。或者在 Web 服务的 API 层,返回一个 500。我们不生产错误,我们只是大自然的搬运工。😛

作为一个负责任的开发者,能处理的错误还是应该尽早处理,这时我们就需要知道究竟出了什么错。标准的 error​ 对象只提供了获取错误消息字符串的接口,通过字符串的内容判断出了什么错,不是一个鲁棒的做法。一些实现友好的库会为每种错误类型定义一个错误对象,比如 sql.ErrNoRows​,调用方可以通过判断错误对象的指针和库中定义的哪个错误对象相等,来判断具体的错误类型。然而,从错误发生到当前位置可能经过了不止一层函数调用,中间某层可能会为了提供更充分的错误现场信息,通过 fmt.Errorf​ 或其他方式构造出新的 error​ 对象。这时就无法通过直接比对指针来判断具体的错误类型了,因为新构造的 error​ 对象不会与任何一个预定义的错误对象相等。

Golang 1.13 版本开始,标准库中提供了新的错误处理机制fmt.Errorf​ 会创建一个实现了 Unwrap()​ 函数的 error​ 对象,Unwrap()​ 函数会返回被封装起来的原始 error​ 对象。为了避免每次都一层一层调用 Unwrap()​函数,标准库中还提供了 errors.Is(err, target error)​ 函数,这个函数会像剥洋葱一样,通过调用 Unwrap()​把封装起来的 err​ 一层层提取出来,依次判断和 target​ 是否相等。

现在还有一个问题,预定义的错误对象创建好之后就不能再更新了,没法在错误信息中加入更具体的信息。加入更具体的信息需要创建新的对象,创建了新的对象就不能再直接与预定义的错误对象判断是否相等了。标准库中其实也提供了解决方案,errors.Is​ 中会判断 err​ 是否实现了 Is(target error) bool​ 这个函数,并尝试用 target​ 作为参数调用这个函数。如果函数返回 true​,那么 errors.Is​ 就会返回 true​。 不过官方文档中并没有提供具体如何利用这个机制的例子,那么我来写一个吧。

var ErrSomethingFailed = errors.New("something failed")

假设我们定义了 ErrSomethingFailed​ 这个对象来表示发生了某种错误。当我们想返回一个包含更具体的错误信息的对象时,可以定义下面这样一个结构体:

type errorSomethingFailedWithReason struct {
	reason string
}

func NewErrorSomethingFailedWithReason(reason string) error {
	return &errorSomethingFailedWithReason{reason}
}

func (e *errorSomethingFailedWithReason) Error() string {
	return fmt.Sprintf("something failed: %s", e.reason)
}

func (e *errorSomethingFailedWithReason) Is(target error) bool {
	if ErrSomethingFailed == target {
		return true
	}
	_, ok := target.(errorSomethingFailedWithReason)
	return ok
}

当发生错误时,可以调用 NewErrorSomethingFailedWithReason​ 来创建一个包含具体错误信息的错误对象 err​,并返回给上层调用方。调用方拿到这个错误对象,调用 errors.Is(err, ErrSomethingFailed)​ 时也会返回 true​,虽然 err​ 和 ErrSomethingFailed​ 并不相等,甚至连它们的实际结构体都不一样。

  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    500 引用 • 1396 回帖 • 252 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 642 关注
  • SEO

    发布对别人有帮助的原创内容是最好的 SEO 方式。

    36 引用 • 200 回帖 • 39 关注
  • Bug

    Bug 本意是指臭虫、缺陷、损坏、犯贫、窃听器、小虫等。现在人们把在程序中一些缺陷或问题统称为 bug(漏洞)。

    76 引用 • 1742 回帖 • 4 关注
  • TGIF

    Thank God It's Friday! 感谢老天,总算到星期五啦!

    291 引用 • 4495 回帖 • 663 关注
  • Ruby

    Ruby 是一种开源的面向对象程序设计的服务器端脚本语言,在 20 世纪 90 年代中期由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)设计并开发。在 Ruby 社区,松本也被称为马茨(Matz)。

    7 引用 • 31 回帖 • 267 关注
  • MongoDB

    MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。

    91 引用 • 59 回帖
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    108 引用 • 153 回帖
  • JWT

    JWT(JSON Web Token)是一种用于双方之间传递信息的简洁的、安全的表述性声明规范。JWT 作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以 JSON 的形式安全的传递信息。

    20 引用 • 15 回帖 • 27 关注
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 233 回帖 • 1 关注
  • TensorFlow

    TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。

    20 引用 • 19 回帖 • 1 关注
  • 京东

    京东是中国最大的自营式电商企业,2015 年第一季度在中国自营式 B2C 电商市场的占有率为 56.3%。2014 年 5 月,京东在美国纳斯达克证券交易所正式挂牌上市(股票代码:JD),是中国第一个成功赴美上市的大型综合型电商平台,与腾讯、百度等中国互联网巨头共同跻身全球前十大互联网公司排行榜。

    14 引用 • 102 回帖 • 314 关注
  • Hprose

    Hprose 是一款先进的轻量级、跨语言、跨平台、无侵入式、高性能动态远程对象调用引擎库。它不仅简单易用,而且功能强大。你无需专门学习,只需看上几眼,就能用它轻松构建分布式应用系统。

    9 引用 • 17 回帖 • 641 关注
  • 开源

    Open Source, Open Mind, Open Sight, Open Future!

    415 引用 • 3596 回帖 • 1 关注
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    125 引用 • 585 回帖
  • 前端

    前端技术一般分为前端设计和前端开发,前端设计可以理解为网站的视觉设计,前端开发则是网站的前台代码实现,包括 HTML、CSS 以及 JavaScript 等。

    246 引用 • 1338 回帖
  • Visio
    1 引用 • 2 回帖 • 2 关注
  • Firefox

    Mozilla Firefox 中文俗称“火狐”(正式缩写为 Fx 或 fx,非正式缩写为 FF),是一个开源的网页浏览器,使用 Gecko 排版引擎,支持多种操作系统,如 Windows、OSX 及 Linux 等。

    7 引用 • 30 回帖 • 376 关注
  • 代码片段

    代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。

    用户在该标签下分享代码片段时需在帖子标题前添加 [css] [js] 用于区分代码片段类型。

    202 引用 • 1467 回帖 • 1 关注
  • Elasticsearch

    Elasticsearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

    117 引用 • 99 回帖 • 197 关注
  • 国际化

    i18n(其来源是英文单词 internationalization 的首末字符 i 和 n,18 为中间的字符数)是“国际化”的简称。对程序来说,国际化是指在不修改代码的情况下,能根据不同语言及地区显示相应的界面。

    8 引用 • 26 回帖
  • InfluxDB

    InfluxDB 是一个开源的没有外部依赖的时间序列数据库。适用于记录度量,事件及实时分析。

    2 引用 • 104 关注
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖 • 1 关注
  • 程序员

    程序员是从事程序开发、程序维护的专业人员。

    591 引用 • 3528 回帖 • 1 关注
  • abitmean

    有点意思就行了

    35 关注
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    34 引用 • 37 回帖 • 559 关注
  • gRpc
    11 引用 • 9 回帖 • 103 关注
  • ActiveMQ

    ActiveMQ 是 Apache 旗下的一款开源消息总线系统,它完整实现了 JMS 规范,是一个企业级的消息中间件。

    19 引用 • 13 回帖 • 684 关注