Go语言error的设计理念及背景演化详解

目录
  • 背景
  • 各语言中 Error 的演化
    • C语言
    • C++
  • Go 中 Error 的理念
    • 1. 区分 Error 和 Exception
    • 2.Error是一个接口
  • 总结

背景

作为一门相对新兴的语言,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)
}

总结

Go 之所以从诞生至今,吸引了这么多的粉丝。处理语言的机制以外,更多的就是它的设计理念。而本文讲述的 error 就是其中一部分。我们在使用 Go 开发时,除了按照它推荐的规范编码至于,还应该关心、理解它的设计。只有这样,才能写出更优秀的作品。

进一步阅读 官方 errors 库文档地址:pkg.go.dev/errors

以上就是Go语言error的设计理念及背景演化详解的详细内容,更多关于Go error设计理念的资料请关注我们其它相关文章!

(0)

相关推荐

  • GoFrame框架数据校验之校验结果Error接口对象

    目录 基本介绍 方法示例 注意问题 方法详解 进阶 注意问题 总结 上一篇文章介绍了 GoFrame数据校验之校验对象 | 校验结构体 ,得到了大家积极的反馈. 再接再厉,这篇总结分享:GoFrame数据校验之校验结果总结分享. 基本介绍 校验结果为一个Error接口对象.当数据规则校验成功时,校验方法返回的结果为nil. 当数据规则校验失败时,返回的该对象是包含结构化的层级map,包含多个字段及其规则及对应错误信息,以便于接收端能够准确定位错误规则. 方法示例 首先我们看一下Error的数据结

  • Go语音开发中常见Error类型处理示例详解

    目录 前言 透明错误处理策略 带来的问题 哨兵(Sentinel)错误处理策略 带来的问题 1.对errors.Error()的依赖 2.定义的错误类型会被公开 Error types 带来的问题 不透明错误处理策略(Opaque errors) 带来的问题 总结 前言 上文我们了解了 Error 在Go 中的设计理念.单从理念上来看, Error 的设计似乎有利于逻辑处理.但实际上,在开发过程中,我们还会遇到各种各样的困难.为了优化开发的流程,开发者们发明了很多处理 Error 的做法.今天我

  • Go error的使用方式详解

    目录 概述 error使用方式 1.直接判等 2.组合error接口,构建更强大的error接口 3.Errno模式 4.Go1.13的Wrap模式 5. Go版本低时的链式error 概述 当我们需要在Go项目中设计error,就不得不先知道Go error几种常用方法.标准库是一个非常好的学习方式,除此之外Go1.13的errors特性也需要掌握. error使用方式 1.直接判等 这里的判等又分为变量判等和类型判等.适用于pkg中预先定义好了多个error变量或类型,err只可能是这些变量

  • 浅谈Go语言的error类型

    error类型是go语言的一种内置类型,使用的时候不用特定去import,他本质上是一个接口 type error interface{ Error() string //Error()是每一个订制的error对象需要填充的错误消息,可以理解成是一个字段Error } 怎样去理解这个订制呢? 我们知道接口这个东西,必须拥有它的实现块才能调用,放在这里就是说,Error()必须得到填充,才能使用. 比方说下面三种方式: 第一种:通过errors包去订制error error := errors.N

  • 一篇文章带你轻松搞懂Golang的error处理

    目录 Golang中的error error的几种玩法 哨兵错误 自定义错误类型 Wrap error Golang1.13版本error的新特性 errors.UnWrap() errors.Is() errors.As() error处理最佳实践 优先处理error 只处理error一次 不要反复包装error 不透明的错误处理 简化错误处理 bufio.scan errWriter 何时该用panic 小补充 总结 Golang中的error Golang中的 error 就是一个简单的接

  • go语言中切片Slice与数组Array对比以及panic: runtime error: index out of range问题解决

    目录 前言 一.go slice是什么 二.go slice实战案例 1.slice创建.使用 2.slice的长度和容量概念理解 3. 切片扩容及slice panic: runtime error: index out of range 附:go 判断数组下标是否存在 总结 前言 在go语言的学习历程当中,slice数据类型引起了我的好奇心.为啥不直接使用Slice,是人性的扭曲还是道德的沦丧~,下面让我们一探究竟~~ 一.go slice是什么 go语言中的slice是一个基于Array封

  • golang常用库之pkg/errors包第三方错误处理包案例详解

    目录 golang常用库之-pkg/errors包 背景 关于官方errors包 官方errors包使用demo 什么是pkg/errors包 pkg/errors包使用demo 优秀开源项目使用案例 参考 golang常用库之-pkg/errors包 背景 golang自带了错误信息包error 只提供了简单的用法, 如errors.New(),和errors.Error()用来传递和获取错误信息. 明显官方的包已经不能满足了, 只能采取其他方法补救, 如:采用三方errors包. 关于官方e

  • Go语言error的设计理念及背景演化详解

    目录 背景 各语言中 Error 的演化 C语言 C++ Go 中 Error 的理念 1. 区分 Error 和 Exception 2.Error是一个接口 总结 背景 作为一门相对新兴的语言,Go 可以说是站在巨人的肩膀上.从 Go 语法上,我们可以看出设计者对其有许多严肃的思考.其中 Error 的处理就是极具标志性的一项. 值得注意的是,Go 中的 Error 一直是一个有争议的内容.很多议案不断的提出又推翻,即便是官方的 error 库也在多个版本中不断迭代.本文内容基于 1.19.

  • R语言关于随机森林算法的知识点详解

    在随机森林方法中,创建大量的决策树. 每个观察被馈入每个决策树. 每个观察的最常见的结果被用作最终输出. 新的观察结果被馈入所有的树并且对每个分类模型取多数投票. 对构建树时未使用的情况进行错误估计. 这称为OOB(袋外)误差估计,其被提及为百分比. R语言包"randomForest"用于创建随机森林. 安装R包 在R语言控制台中使用以下命令安装软件包. 您还必须安装相关软件包(如果有). install.packages("randomForest") 包&qu

  • C语言 OutputDebugString与格式化输出函数OutputDebugPrintf案例详解

    OutputDebugString属于windows API的,所以只要是包含了window.h这个头文件后就可以使用了.可以把调试信息输出到编译器的输出窗口,还可以用DbgView(本机或TCP远程)这样的工具查看,这样就可以脱离编译器了.   OutputDebugString 默认只能输入一个参数,不能像printf那样格式化输出,下面改造成类似printf函数的输出方式. #include <windows.h> #include <stdio.h> //#include

  • R语言学习ggplot2绘制统计图形包全面详解

    目录 一.序 二.ggplot2是什么? 三.ggplot2能画出什么样的图? 四.组装机器 五.设计图纸 六.机器的零件 1. 零件--散点图 1) 变换颜色 2) 拟合曲线 3) 变换大小 4) 修改透明度 5) 分层 6) 改中文 2. 零件--直方图与条形图 1) 直方图 2) 润色 3) 条形图 3. 零件--饼图 4. 零件--箱线图 5. 零件--小提琴图 6. 零件打磨 7. 超级变变变 8. 其他常用零件 七.实践出真知 八.学习资源 九.参考资料 一.序 作为一枚统计专业的学

  • Go语言开发redis封装及简单使用详解

    目录 go redis 集合操作--sadd 安装redigo 带密码的redis操作 批量添加 无密码redis操作 redis封装包 参考 go redis 集合操作--sadd redis的go语言包,我们使用官方推荐的redigo,https://github.com/garyburd/redigo 安装redigo $ go get github.com/garyburd/redigo 带密码的redis操作 package main import ( "log" "

  • C语言递归思想实现汉诺塔详解

    目录 1.递归思想简介 2.汉诺塔问题 3.汉诺塔递归的c语言实现 总结 1.递归思想简介 在c语言中,程序调用自身的编程技巧称为递归( recursion). 递归的定义看上去似乎很抽象,使用代码描述能够让人容易理解,下面是一个函数递归的例子. /* 递归求n的阶乘 */ int factorial(int n) //定义一个求阶乘的函数叫做factorial(),需要一个整形参数,返回一个整形值 { if (n <= 1) //递归结束的条件 { return 1; } else { ret

  • go语言context包功能及操作使用详解

    目录 Context包到底是干嘛用的? context原理 什么时候应该使用 Context? 如何创建 Context? 主协程通知有子协程,子协程又有多个子协程 context核心接口 emptyCtx结构体 Backgroud TODO valueCtx结构体 WithValue向context添加值 Value向context取值 示例 WithCancel可取消的context cancelCtx结构体 WithDeadline-超时取消context WithTimeout-超时取消

  • Go语言学习笔记之文件读写操作详解

    目录 文件写 文件读 小结 文件操作比较多,分为几篇来写吧.首先是文件的读写,在平时的工程化操作中使用最多. 文件写 样例代码如下 package main import ( "bufio" "fmt" "io" "os" ) //写文件 func DoWriteFile() error { _filePath := "./test.txt" _file, _err := os.OpenFile(_file

  • C语言中进程间通讯的方式详解

    目录 一.无名管道 1.1无名管道的原理 1.2功能 1.3无名管道通信特点 1.4无名管道的实例 二.有名管道 2.1有名管道的原理 2.2有名管道的特点 2.3有名管道实例 三.信号 3.1信号的概念 3.2发送信号的函数 3.3常用的信号 3.4实例 四.IPC进程间通信 4.1IPC进程间通信的种类 4.2查看IPC进程间通信的命令 4.3消息队列 4.4共享内存 4.5信号灯集合 一.无名管道 1.1无名管道的原理 无名管道只能用于亲缘间进程的通信,无名管道的大小是64K.无名管道是内

  • Go语言数据结构之单链表的实例详解

    目录 任意类型的数据域 实例01 快慢指针 实例02 反转链表 实例03 实例04 交换节点 实例05 任意类型的数据域 之前的链表定义数据域都是整型int,如果需要不同类型的数据就要用到 interface{}. 空接口 interface{} 对于描述起不到任何的作用(因为它不包含任何的method),但interface{}在需要存储任意类型的数值的时候相当有用,因为它可以存储任意类型的数值. 一个函数把interface{}作为参数,那么它可以接受任意类型的值作为参数:如果一个函数返回i

随机推荐