Go语言error的设计理念及背景演化详解
作者:bluesGavin 发布时间:2024-02-09 22:09:19
背景
作为一门相对新兴的语言,Go 可以说是站在巨人的肩膀上。从 Go 语法上,我们可以看出设计者对其有许多严肃的思考。其中 Error 的处理就是极具标志性的一项。
值得注意的是,Go 中的 Error 一直是一个有争议的内容。很多议案不断的提出又推翻,即便是官方的 error 库也在多个版本中不断迭代。本文内容基于 1.19.3 版本的 Go 编写。
各语言中 Error 的演化
想要了解 Error 在 Go 中占据话题的原因,我们需要先了解 Error 在编程语言中的演化。
C语言
C语言中开发者需要根据函数的返回值作错误判断。每个函数是单返回值,一般通过传递指针作为入参。返回值为 int 类型,表示成功或失败。
显然在这个阶段,语言设计者只单纯地把错误考虑为“异常”情况,由开发者判断函数的执行结果。这种情况下,错误中并没有太多信息。这会加重开发者对错误的处理工作。
C++
进入C++时代以后,语言带来了 exception 。错误会作为一个程序正常执行以外的一个特殊情况被抛出。而开发者可以通过 try....catch.... 对异常作特殊处理。
这种设计模式的影响很广,包括 Javascript 在内很多语言都延续了这种设计。其特点为,开发者可以知道错误在哪里抛出,但不能具体知道调用方会抛出什么异常。
Go 中 Error 的理念
在 Go 的 Error 中,我们可以看到两个 ERROR 的特点。
1. 区分 Error 和 Exception
第一点是,Go 中真正从语言设计上区分开了 Error 和 Exception。Go 的处理异常逻辑不引入 exception ,支持多参数返回,所以开发者可以很容易在函数签名中带上实现了 error interface 的对象,交由调用者处理。
通常如果一个函数返回了 value 和 error , 开发者需要先判定 error,再利用处理 value 处理下一步逻辑。常见代码如下:
value, err := getSomething()
if err != nil{
// 处理错误
return
}
// 逻辑处理
另外,Go 中引入了 panic 机制,它与其他语言的 exception 不完全一样。在其他语言中,当程序抛出异常时,相当于把 exception 抛给开发者处理。而 Go 中的 panic 是专门,针对真正意外,不可恢复的情况,如索引越界、不可恢复的环境问题、栈溢出。
同时,GO 也提供了从 panic 中恢复的接口—— recover 。但这不意味着开发者应该把其当作 try... catch... 使用。而是应该当作是程序崩溃后的特殊处理的最后机会。在 Go 的设计中,panic 一旦触发,说明程序应该要退出了。但在某些业务场景下,我们可能还会有日志上报,日志打印,信息通知等操作。此时,就应该考虑使用 recover。
2.Error是一个接口
第二点是,Error 在 Go 中其实是一个普通的接口。它不仅保存着错误的信息,还提供了一系列的方式供开发者使用。因此开发者可以自行拓展,嵌套,封装新的 error ,为项目提供自定义错误模块。
由此看来,Error 在 Go 中并不像其他语言一样,是一个特殊的类型。它只是一个普通的值,开发者完全可以自己实现一套新的 Error 接口。但更多时候,官方的 errors 库已经可以覆盖绝大多数场景了。
因此, Go 的设计并不是在定义一套新的 Error 机制。而是在制定一套 Error 在代码逻辑中处理的规范。你不必完全遵守这套规范,但在各种实际开发经验总结来看,Go 的这种设计模式确实赢得了很多开发者的青睐。
示例代码:
// 创建一个error
newErr := errors.New("一个错误")
// 判断error类型
if errors.Is(newErr, fs.ErrNotExist) {
fmt.Println("file does not exist")
} else {
fmt.Println(err)
}
来源:https://juejin.cn/post/7173983851692163102


猜你喜欢
- 本文实例讲述了Python3使用requests模块实现显示下载进度的方法。分享给大家供大家参考,具体如下:一、配置request1. 相关
- 1、建立socket建立socket对象需要搞清通信类型和协议家族。通信类型指明了用什么协议来传输数据。协议的例子包括IPv4、IPv6、I
- 运行方法: 1. 打开python2 IDLE; 2. 输入 fro
- DBA_2PC_PENDING Oracle会自动处理分布事务,保证分布事务的一致性,所有站点全部提交或全部回滚。一般情况下,处理过程在很短
- 前言select作为Go chan通信的重要监听工具,有着很广泛的使用场景。select的使用主要是搭配通信case使用,表面上看,只是简单
- 项目地址:https://github.com/MrWayneLee/weather-demo代码部分下载生成文件功能# 下载并生成文件de
- 这几天想统计一下《中国人文社会科学期刊 AMI 综合评价报告(2018 年):A 刊评价报告》中的期刊,但是只找到了该报告的PDF版,对于表
- 先来看看效果: Html源码:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Tr
- JS获取网页中HTML元素的几种方法分析:getElementById getElementsByName getElementsByTag
- 使用了python中的pexpect模块,在测试代码之前,可输入python进入交互界面,输入help('pexpect')
- 引言最近遭遇了绑定手机号相关的压测需求,有了手机号登录的经验和测试数据,这次算起来比较简单。最重要的是难点就是要求开发配合调整配置已经在上一
- 前言在写程序时,我们会经常碰到程序出现异常,这时候我们就不得不处理这些异常,以保证程序的健壮性。处理异常的版本有以下几种,你通常的做法是哪种
- 本文研究的主要是Django使用httpresponse返回用户头像,下面是相关实例代码。当请求一个页面时,Django 把请求的 meta
- atan()方法返回x的反正切值,以弧度表示。Syntax以下是atan()方法的语法:atan(x)注意:此函数是无法直接访问
- 作为一种常见的数据结构,缓冲区(Buffer)在计算机科学中有着广泛的应用。Go 语言标准库中提供了一个名为 bytes.Buffer 的缓
- 目的:基于办公与互联网隔离,自带的office软件没有带本地帮助工具,因此在写vba程序时比较不方便(后来发现07有自带,心中吐血,瞎折腾些
- 给每一个onClick再附加一个事件 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HT
- 还原一个数据库:mysql -h localhost -u root -p123456 www<c:\www.sql 备份一个数据库:
- 假如有一列全是字符串的dataframe,希望提取包含特定字符的所有数据,该如何提取呢?因为之前尝试使用filter,发现行不通,最终找到这
- 简介vue.js是由华人尤雨溪开发的一套MVVM框架。vue.js 的核心是一个允许你采用简洁的模板语法来声明式的将数据渲染进 DOM 的系