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

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 发布的第二款编程语言。

    497 引用 • 1388 回帖 • 279 关注

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • Webswing

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

    1 引用 • 15 回帖 • 637 关注
  • uTools

    uTools 是一个极简、插件化、跨平台的现代桌面软件。通过自由选配丰富的插件,打造你得心应手的工具集合。

    6 引用 • 14 回帖
  • CongSec

    本标签主要用于分享网络空间安全专业的学习笔记

    1 引用 • 1 回帖 • 17 关注
  • Kafka

    Kafka 是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是现代系统中许多功能的基础。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。

    36 引用 • 35 回帖
  • Node.js

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

    139 引用 • 269 回帖 • 28 关注
  • 百度

    百度(Nasdaq:BIDU)是全球最大的中文搜索引擎、最大的中文网站。2000 年 1 月由李彦宏创立于北京中关村,致力于向人们提供“简单,可依赖”的信息获取方式。“百度”二字源于中国宋朝词人辛弃疾的《青玉案·元夕》词句“众里寻他千百度”,象征着百度对中文信息检索技术的执著追求。

    63 引用 • 785 回帖 • 164 关注
  • Typecho

    Typecho 是一款博客程序,它在 GPLv2 许可证下发行,基于 PHP 构建,可以运行在各种平台上,支持多种数据库(MySQL、PostgreSQL、SQLite)。

    12 引用 • 65 回帖 • 445 关注
  • 自由行
    4 关注
  • Vditor

    Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript、Vue、React 和 Angular。

    354 引用 • 1823 回帖 • 1 关注
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖 • 6 关注
  • Gitea

    Gitea 是一个开源社区驱动的轻量级代码托管解决方案,后端采用 Go 编写,采用 MIT 许可证。

    4 引用 • 16 回帖
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    83 引用 • 37 回帖
  • GitLab

    GitLab 是利用 Ruby 一个开源的版本管理系统,实现一个自托管的 Git 项目仓库,可通过 Web 界面操作公开或私有项目。

    46 引用 • 72 回帖
  • Chrome

    Chrome 又称 Google 浏览器,是一个由谷歌公司开发的网页浏览器。该浏览器是基于其他开源软件所编写,包括 WebKit,目标是提升稳定性、速度和安全性,并创造出简单且有效率的使用者界面。

    62 引用 • 289 回帖
  • 招聘

    哪里都缺人,哪里都不缺人。

    190 引用 • 1057 回帖
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖 • 6 关注
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 745 关注
  • Caddy

    Caddy 是一款默认自动启用 HTTPS 的 HTTP/2 Web 服务器。

    12 引用 • 54 回帖 • 158 关注
  • 面试

    面试造航母,上班拧螺丝。多面试,少加班。

    325 引用 • 1395 回帖
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3190 引用 • 8214 回帖 • 1 关注
  • 微服务

    微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。

    96 引用 • 155 回帖 • 1 关注
  • 国际化

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

    8 引用 • 26 回帖 • 1 关注
  • HTML

    HTML5 是 HTML 下一个的主要修订版本,现在仍处于发展阶段。广义论及 HTML5 时,实际指的是包括 HTML、CSS 和 JavaScript 在内的一套技术组合。

    107 引用 • 295 回帖
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 538 关注
  • PWL

    组织简介

    用爱发电 (Programming With Love) 是一个以开源精神为核心的民间开源爱好者技术组织,“用爱发电”象征开源与贡献精神,加入组织,代表你将遵守组织的“个人开源爱好者”的各项条款。申请加入:用爱发电组织邀请帖
    用爱发电组织官网:https://programmingwithlove.stackoverflow.wiki/

    用爱发电组织的核心驱动力:

    • 遵守开源守则,体现开源&贡献精神:以分享为目的,拒绝非法牟利。
    • 自我保护:使用适当的 License 保护自己的原创作品。
    • 尊重他人:不以各种理由、各种漏洞进行未经允许的抄袭、散播、洩露;以礼相待,尊重所有对社区做出贡献的开发者;通过他人的分享习得知识,要留下足迹,表示感谢。
    • 热爱编程、热爱学习:加入组织,热爱编程是首当其要的。我们欢迎热爱讨论、分享、提问的朋友,也同样欢迎默默成就的朋友。
    • 倾听:正确并恳切对待、处理问题与建议,及时修复开源项目的 Bug ,及时与反馈者沟通。不抬杠、不无视、不辱骂。
    • 平视:不诋毁、轻视、嘲讽其他开发者,主动提出建议、施以帮助,以和谐为本。只要他人肯努力,你也可能会被昔日小看的人所超越,所以请保持谦虚。
    • 乐观且活跃:你的努力决定了你的高度。不要放弃,多年后回头俯瞰,才会发现自己已经成就往日所仰望的水平。积极地将项目开源,帮助他人学习、改进,自己也会获得相应的提升、成就与成就感。
    1 引用 • 487 回帖 • 2 关注
  • 电影

    这是一个不能说的秘密。

    121 引用 • 604 回帖
  • 单点登录

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

    9 引用 • 25 回帖