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

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

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 关注

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • VirtualBox

    VirtualBox 是一款开源虚拟机软件,最早由德国 Innotek 公司开发,由 Sun Microsystems 公司出品的软件,使用 Qt 编写,在 Sun 被 Oracle 收购后正式更名成 Oracle VM VirtualBox。

    10 引用 • 2 回帖 • 16 关注
  • 以太坊

    以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约、开源的底层系统。以太坊是一个平台和一种编程语言 Solidity,使开发人员能够建立和发布下一代去中心化应用。 以太坊可以用来编程、分散、担保和交易任何事物:投票、域名、金融交易所、众筹、公司管理、合同和知识产权等等。

    34 引用 • 367 回帖 • 1 关注
  • Anytype
    3 引用 • 31 回帖 • 27 关注
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    284 引用 • 248 回帖
  • jsDelivr

    jsDelivr 是一个开源的 CDN 服务,可为 npm 包、GitHub 仓库提供免费、快速并且可靠的全球 CDN 加速服务。

    5 引用 • 31 回帖 • 107 关注
  • 单点登录

    单点登录(Single Sign On)是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

    9 引用 • 25 回帖 • 3 关注
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 440 关注
  • InfluxDB

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

    2 引用 • 104 关注
  • SpaceVim

    SpaceVim 是一个社区驱动的模块化 vim/neovim 配置集合,以模块的方式组织管理插件以
    及相关配置,为不同的语言开发量身定制了相关的开发模块,该模块提供代码自动补全,
    语法检查、格式化、调试、REPL 等特性。用户仅需载入相关语言的模块即可得到一个开箱
    即用的 Vim-IDE。

    3 引用 • 31 回帖 • 112 关注
  • 生活

    生活是指人类生存过程中的各项活动的总和,范畴较广,一般指为幸福的意义而存在。生活实际上是对人生的一种诠释。生活包括人类在社会中与自己息息相关的日常活动和心理影射。

    230 引用 • 1432 回帖
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖 • 2 关注
  • sts
    2 引用 • 2 回帖 • 243 关注
  • CodeMirror
    2 引用 • 17 回帖 • 173 关注
  • Git

    Git 是 Linux Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

    211 引用 • 358 回帖 • 2 关注
  • SQLServer

    SQL Server 是由 [微软] 开发和推广的关系数据库管理系统(DBMS),它最初是由 微软、Sybase 和 Ashton-Tate 三家公司共同开发的,并于 1988 年推出了第一个 OS/2 版本。

    21 引用 • 31 回帖 • 1 关注
  • C

    C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

    86 引用 • 165 回帖
  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    142 引用 • 442 回帖
  • ZooKeeper

    ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是 Hadoop 和 HBase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

    61 引用 • 29 回帖 • 10 关注
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    4 引用 • 7 回帖
  • 七牛云

    七牛云是国内领先的企业级公有云服务商,致力于打造以数据为核心的场景化 PaaS 服务。围绕富媒体场景,七牛先后推出了对象存储,融合 CDN 加速,数据通用处理,内容反垃圾服务,以及直播云服务等。

    29 引用 • 230 回帖 • 124 关注
  • Mac

    Mac 是苹果公司自 1984 年起以“Macintosh”开始开发的个人消费型计算机,如:iMac、Mac mini、Macbook Air、Macbook Pro、Macbook、Mac Pro 等计算机。

    167 引用 • 597 回帖 • 1 关注
  • 服务器

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

    125 引用 • 585 回帖
  • 负能量

    上帝为你关上了一扇门,然后就去睡觉了....努力不一定能成功,但不努力一定很轻松 (° ー °〃)

    89 引用 • 1251 回帖 • 393 关注
  • 一些有用的避坑指南。

    69 引用 • 93 回帖
  • 创造

    你创造的作品可能会帮助到很多人,如果是开源项目的话就更赞了!

    186 引用 • 1021 回帖
  • QQ

    1999 年 2 月腾讯正式推出“腾讯 QQ”,在线用户由 1999 年的 2 人(马化腾和张志东)到现在已经发展到上亿用户了,在线人数超过一亿,是目前使用最广泛的聊天软件之一。

    45 引用 • 557 回帖
  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖 • 1 关注