Golang 中 Error 的设计及最佳实践

如果你对于 Go 的 Error 设计不太熟悉也不习惯,为什么许多接口都需要返回 error 接口类型的值呢?什么时候该处理 error,什么时候该抛出 error,什么时候又该忽略 error ?Go 设计者又为什么要这样设计 error 呢?想必刚接触 Golang 的同学也会和我一样有类似的疑惑,在读了 TGPL 以及 Go Blog 相关的章节/内容后,我尝试回答一下这些问题。
在第 1 、2小节我将尝试回答 error 是什么,它是如何设计的,以及为什么这样设计。
在第 3 小节我将回答在 Coding 时,如何处理错误。

Error 是什么?

在 Go built-in 包中,Error 被设计为一个接口。

// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
type error interface {Error() string
}
Go 的设计理念是:失败(failure)只是一种常见的行为。因此对于那些失败被视作理所当然的函数可以返回一个额外的结果——error,通常是最后一个返回值。而如果失败只有一种可能的原因,那么只需要返回一个 bool 值即可。

上述做法在 Go 的源码或接口设计中很常见。举两个例子:
以常见的 Reader 接口为例, Read 方法读取至多 len§ 个字节到 p 中,返回读取的字节数 n 和读取过程中可能发生的错误 err。

type Reader interface {Read(p []byte) (n int, err error)
}

当我们使用 map 时经常遇到的一种情况是:确定某个键是否在 map 中。但是 map 在该键不存在时也会返回默认值,此时可以使用带 bool 返回值的形式:

if val, ok := m["key"]; ok {// do something
} else {// do other things
}

Error 的设计

Go 的错误处理设计与其他语言的异常不同。Go 中的 error 就是一个普通的值对象,而其他语言如 Java 中的 Exception 将会造成程序控制流的终止和其他行为,Exception 与普通的值不同。虽然 Go 也有类似的异常机制 —— panic,但它仅用于报告完全无法预料的错误(可能有 Bug),而不应该是一个健壮程序应该返回的程序错误(这一点与 Java 等语言不同)。
关于 Go 为什么这样设计的原因,Kernighan 在 《The Go Programming Language》中给出解释:“The reason for this design is that exceptions tend to entangle the description of an error with the control flow required to handle it, often leading to an undesirable outcome: routine errors are reported to the end user in the form of an incomprehensible stack trace, full of information about the structure of the program but lacking intelligible context about what went wrong”。

即:因为异常会将错误的描述和处理错误的控制流纠缠在一起,通常会导致程序错误以一种难以理解的栈追踪的方式被报告给终端用户,这种方式充满了程序结构的信息,但是缺少关于哪里出错的易于理解的上下文信息。

相反,Go 程序使用普通的程序控制流机制如 if 以及 return 来对 error 作出响应,这种设计虽然要求 Gophers 更加关注错误处理逻辑,但这正是它想做到的点。即“好的程序应该考虑到所有可能的错误,并且对其进行处理”。
🤔 Go 将 error 设计为一个接口,只需要实现 Error() string 方法,返回有意义、简练的错误描述信息即可。这也使得我们可以以任何的方式来自定义错误。
Tips: 建议在底层只需要返回清晰地错误信息,每一层包裹一些重要并且简洁的上下文信息,并且最终在程序的顶层或者某一个不得不处理的层级处理该错误。
正是这种方式,在 Go 中也将这种层层包裹的错误称之为错误链。由此,在 Go 1.13 之后出现了一些新的设计以支持这种错误链的处理方式。其中最简单的错误链就是如下所述的层层包裹的文本信息(或者程序调用栈信息)
arduino复制代码genesis: crashed: no parachute: G-switch failed: bad relay orientation

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/118641.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

边缘计算:云计算的延伸

云计算已经存在多年,并已被证明对大大小小的企业都有好处;然而,直到最近边缘计算才变得如此重要。它是指发生在网络边缘的一种数据处理,更接近数据的来源地。 这将有助于提高效率并减少延迟以及设备和云之间的数据传输成本。边缘…

EtherNet Ip工业RFID读写器与欧姆龙PLC 配置示例说明

一、准备阶段 POE交换机欧姆龙PLC 支持EtherNet Ip协议CX-Programmer 9.5配置软件 二、配置读卡器 1、打开软件 2、选择网卡,如果多网卡的电脑请注意对应所接的网卡,网卡名一般为“Network adapter Realtek PCIe GBE Family” 3、点击“选择网卡”&…

douyin ios 六神参数学习记录

玩那么久安卓了,也终于换一换ios终端分析分析,还是熟悉的x-gorgon,x-argus,x-medusa那些参数。 随便抓个抖音 ios版本的接口: 像评论接口: https://api26-normal-hl.amemv.com/aweme/v2/comment/list/?…

XTU-OJ 1187-Candy

WCB某天买了非常多的糖果并把它们分成N份,依次分别有1,2,3…,N个糖果。他想拿出其中的3份分给他的室友, 为了不让室友们闹意见,必须让这三份的糖果总数恰好能被三人均分。请问他一共有多少种不同的组合方案数&#xff…

机器学习之查准率、查全率与F1

文章目录 查准率(Precision):查全率(Recall):F1分数(F1 Score):实例P-R曲线F1度量python实现 查准率(Precision): 定义: …

Linux命令记载

服务器基本操作 SSH登录服务器 ssh -p 端口号 用户名服务器IP sftp>get /usr/test.txtSFTP上传文件 #输入密码 #使用get命令下载远程服务器的文件,比如/usr/test.txt sftp>get /usr/test.txt#使用put命令上传本地文件到服务器,比如/usr/test1.t…

低概率Bug,研发敷衍说复现不到

测试工作中,经常会遇到一些低概率出现的问题,如果再是个严重问题,那测试人员的压力无疑是很大的,一方面是因为低概率难以复现,另一面则是来自项目组的压力。 如何在测试时减少此类问题的重复投入,我的思考如…

自研框架跻身全球 JS 框架榜单,排名紧随 React、Angular 之后!

前言 终于实现了一个重要目标!我独立研发的 JavaScript 框架 Strve,最近发布了重大版本 6.0.2。距离上次大版本发布已经接近两个月,期间进行了大量的优化,使得框架性能和稳定性都得到了大幅度的提升。在上次的大版本更新中&#…

nodejs | js | ts | axios |下载远程链接图片

原理: 获取二进制流写入文件 import axios from axios; import fs from fs; export async function downloadImage(url: string, filename: string) {try {const response await axios.get(url, { responseType: stream });response.data.pipe(fs.createWriteStream(filename)…

css 两栏布局的实现

目录 前言 1. 浮动布局 用法 代码示例 理解 2. Flex布局 用法 代码示例 理解 3. Grid布局 用法 代码示例 理解 高质量的设计 前言 两栏布局是一种常见的网页设计模式,它将页面分为两个主要区域:主内容区域和侧边栏。这种布局方式不仅能够提…

天堂2游戏出错如何解决

运行游戏时出现以下提示:“the game may not be consistant because AGP is deactivated please activate AGP for consistancy” 这个问题的原因可能是由于您的显示卡的驱动或者主板的显示芯片组的驱动不是新开。或您虽然已经更新了您的显示卡的驱动程序&#xff0…

nodejs+vue城市轨道交通线路查询系统-计算机毕业设计

着社会的快速发展,计算机的影响是全面且深入的。社会生产水平的不断提高,日常生活中人们对备忘记账系统方面的要求也在不断提高,因特网的使用越来越广泛,而在众多的因特网中,万维网更是为人们带来了新鲜的体验。在这当…

在docker环境下从头搭建openvslam/orb_slam3的流程记录以及问题总结

文章目录 0. 前言1. MobaXterm软件2. docker操作2.1. 拉一个ubuntu镜像2.2. 修改名字(可选)2.3. 删除之前的docker镜像(可选) 3. openvslam搭建流程3.1. 起容器3.2. 前置包的安装3.3. 安装Eigen3.4. 安装opencv3.5. 安装DBoW23.6.…

MySQL——九、SQL编程

MySQL 一、触发器1、触发器简介2、创建触发器3、一些常见示例 二、存储过程1、什么是存储过程或者函数2、优点3、存储过程创建与调用 三、存储函数1、存储函数创建和调用2、修改存储函数3、删除存储函数 四、游标1、声明游标2、打开游标3、使用游标4、关闭游标游标案例 一、触发…

Flutter extended_image库设置内存缓存区大小与缓存图片数

ExtendedImage ExtendedImage 是一个Flutter库,用于提供高级图片加载和显示功能。这个库使用了 image 包来进行图片的加载和缓存。如果你想修改缓存大小,你可以通过修改ImageCache的配置来实现。 1. 获取ImageCache实例: 你可以通过PaintingBinding…

deeplearning4j训练推理案例2023——手写数字识别

文章目录 1.minist数据集2.依赖包3.手写数字训练与推理4. 扩展阅读deeplearning4j自带学习案例项目deeplearning4j-examples 1.minist数据集 下载链接 6W训练集,1W测试集 2.依赖包 主要是deeplearning4j、javacv的一些包,案例打出的jar包1.3G,pom来自…

超级强大!送你几款Linux 下终极SSH客户端

更多IT技术,请关注微信公众号:“运维之美” 超级强大!送你几款Linux 下终极SSH客户端 1.MobaXterm2.Xshell3.SecureCRT4.PuTTY5.FinalShell6.Termius7.WindTerm 安全外壳协议(Secure Shell,简称 SSH)是一种网络连接协议…

【Gensim概念】02/3 NLP玩转 word2vec

第二部分 句法 六、句法模型(类对象和参数) 6.1 数据集的句子查看 classgensim.models.word2vec.BrownCorpus(dirname) Bases: object 迭代句子 Brown corpus (part of NLTK data). 6.2 数据集的句子和gram classgensim.models.word2vec.Heapitem(c…

【Docker】Docker数据的存储

默认情况下,在运行中的容器里创建的文件,被保存在一个可写的容器层里,如果容器被删除了,则对应的数据也随之删除了。 这个可写的容器层是和特定的容器绑定的,也就是这些数据无法方便的和其它容器共享。 Docker主要提…

智能井盖监测系统功能,万宾科技传感器效果

智能井盖传感器的出现是高科技产品的更新换代,同时也是智慧城市建设中的需求。在智慧城市建设过程之中,高科技产品的应用数不胜数,智能井盖传感器的出现,解决了城市道路安全保护着城市地下生命线,改善着传统井盖带来的…