Go的错误处理
什么是错误?
错误表示程序中发生的任何异常情况。假设我们正在尝试打开一个文件,但该文件在文件系统中不存在。这是一种异常情况,表示为错误。
Go 中的错误是普通的旧值。就像任何其他内置类型(例如 int、float64 等)一样,错误值可以存储在变量中、作为参数传递给函数、从函数返回等。
错误使用内置error
类型表示。我们将在本教程后面详细了解该error
类型。
例子
让我们立即开始尝试打开一个不存在的文件的示例程序。
package mainimport ( "fmt""os"
)func main() { f, err := os.Open("/test.txt")if err != nil {fmt.Println(err)return}fmt.Println(f.Name(), "opened successfully")
}
Run in playground
在上面程序的第 9 步中,我们尝试打开路径中的文件/test.txt
(该文件显然不会存在于 Playground 中)。包的*Open*函数os
具有以下签名,
*func Open(名称字符串) (File, error)
如果文件已成功打开,则 Open 函数将返回文件处理程序,错误将为 nil。如果打开文件时出现错误,将返回非零错误。
如果函数或方法返回错误,那么按照惯例,它必须是函数返回的最后一个值。因此该Open
函数返回error
最后一个值。
**Go 中处理错误的惯用方法是将返回的错误与nil
. nil 值表示没有发生错误,非 nil 值表示存在错误。**在我们的例子中,
我们检查错误是否不等于nil
。如果不是nil
,我们只需打印错误并从主函数返回。
运行该程序将打印
open /test.txt: No such file or directory
完美😃。我们收到一条错误消息,指出该文件不存在。
错误类型表示
让我们更深入地研究一下内置error
类型是如何定义的。error是具有以下定义的接口类型
type error interface { Error() string
}
它包含一个带有签名的方法Error() string
。任何实现此接口的类型都可以用作错误。此方法提供错误的描述。
当打印错误时,fmt.Println
函数内部调用该Error() string
方法来获取错误的描述打印方式
从错误中提取更多信息的不同方法
现在我们知道了error
是一个接口类型,让我们看看如何提取有关错误的更多信息。
在上面的示例中,我们刚刚打印了错误的描述。如果我们想要导致错误的文件的实际路径怎么办?获取此信息的一种可能方法是解析错误字符串。这是我们程序的输出,
open /test.txt: No such file or directory
我们可以解析此错误消息并获取导致错误的文件的文件路径“/test.txt”,但这是一种肮脏的做法。在较新版本的 Go 中,错误描述可能随时更改,我们的代码将会崩溃。
有没有更好的方法来获取文件名🤔?答案是肯定的,这是可以做到的,并且 Go 标准库使用不同的方式来提供有关错误的更多信息。让我们一一看看。
1. 将错误转换为基础类型并从结构体字段中检索更多信息
如果你仔细阅读Open函数的文档,你会发现它返回一个类型为*PathError.
PathError的错误,它是一个结构体类型,它在标准库中的实现如下:
type PathError struct { Op stringPath stringErr error
}func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }
如果您有兴趣知道上述源代码存在于哪里,可以在这里找到https://cs.opensource.google/go/go/+/refs/tags/go1.19:src/io/fs/fs .go;l=250
从上面的代码中,你可以明白,是通过声明方法*PathError
来实现的。此方法将操作、路径和实际错误连接起来并返回。因此我们得到了错误消息,error interface``Error() string
open /test.txt: No such file or directory
Path
struct 字段 包含PathError
导致错误的文件的路径。
我们可以使用errors包中的As函数将错误转换为其基础类型。该As
函数的描述谈到了错误链。请暂时忽略它。我们将在单独的教程中了解错误链和包装的工作原理。
简单的描述As
是,它尝试将错误转换为错误类型,并返回 true 或 false 指示转换是否成功。
一个程序会让事情变得清晰。让我们修改上面编写的程序并使用该As
函数打印路径。
package mainimport ( "errors""fmt""os"
)func main() { f, err := os.Open("test.txt")if err != nil {var pErr *os.PathErrorif errors.As(err, &pErr) {fmt.Println("Failed to open file at path", pErr.Path)return}fmt.Println("Generic error", err)return}fmt.Println(f.Name(), "opened successfully")
}
Run in playground
在上面的程序中,我们首先检查错误是否不在nil
, 然后我们使用As
的函数。 转换err
为*os.PathError
.
如果转换成功,As
将返回true
。
如果您想知道为什么pErr
是指针,原因是错误接口是由指针实现的PathError
,因此pErr
是指针。下面的代码显示了*PathError
错误接口的实现。
func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }
该As
函数要求第二个参数是指向实现错误的类型的指针。因此我们通过了&perr
。
该程序输出,
Failed to open file at path test.txt
如果底层错误不是*os.PathError
类型,则打印一般错误消息。
太棒了😃。我们已经成功地使用该As
函数从错误中获取文件路径。
2. 使用方法检索更多信息
从错误中获取更多信息的第二种方法是找出基础类型并通过调用结构类型上的方法来获取更多信息。
让我们通过一个例子更好地理解这一点。
标准库中的DNSError*结构*类型定义如下:
type DNSError struct { ...
}func (e *DNSError) Error() string { ...
}
func (e *DNSError) Timeout() bool { ...
}
func (e *DNSError) Temporary() bool { ...
}
该DNSError
结构有两个方法Timeout() bool
,Temporary()
它们返回一个布尔值,指示错误是由于超时还是临时错误。
让我们编写一个程序,将错误转换为*DNSError
类型,并调用上述方法来确定错误是暂时的还是由于超时造成的。
package mainimport ( "errors""fmt""net"
)func main() { addr, err := net.LookupHost("baidu12345.com")if err != nil {var dnsErr *net.DNSErrorif errors.As(err, &dnsErr) {if dnsErr.Timeout() {fmt.Println("operation timed out")return}if dnsErr.Temporary() {fmt.Println("temporary error")return}fmt.Println("Generic DNS error", err)return}fmt.Println("Generic error", err)return}fmt.Println(addr)
}
注意:DNS 查找在 Playground 中不起作用。请在您的本地计算机上运行该程序。
在上面的程序中,我们正在尝试获取无效域名的IP地址baidu123.com
。我们通过使用As
该函数并将其转换为DNSError
来 获取错误的基本值。然后我们分别在14和18行检查错误是由于超时还是暂时错误的。
在我们的例子中,错误既不是暂时的,也不是由于超时造成的,因此程序将打印:
Generic DNS error lookup baidu12345.com: no such host
如果错误是暂时的或者由于超时,那么相应的 if 语句就会执行,我们可以适当地处理它。
3. 直接比较
获取有关错误的更多详细信息的第三种方法是直接与 类型的变量进行比较error
。让我们通过一个例子来理解这一点。
包的Glob函数filepath
用于返回与某个模式匹配的所有文件的名称。当模式格式错误时,此ErrBadPattern
函数将返回错误。
ErrBadPattern在包中定义filepath
为全局变量。
var ErrBadPattern = errors.New("syntax error in pattern")
error.New() 用于创建一个新错误。我们将在下一个教程中详细讨论这一点。
当模式格式错误时,Glob 函数将返回ErrBadPattern 。
让我们编写一个小程序来检查此错误。
package mainimport ( "errors""fmt""path/filepath"
)func main() { files, err := filepath.Glob("[")if err != nil {if errors.Is(err, filepath.ErrBadPattern) {fmt.Println("Bad pattern error:", err)return}fmt.Println("Generic error:", err)return}fmt.Println("matched files", files)
}
Run in playground
在上面的程序中,我们搜索格式[
错误的模式文件。我们检查错误是否不为nil。为了获得有关错误的更多信息,我们直接使用Is函数将filepath.ErrBadPattern
inline 进行比较。与 类似As
,该Is
函数在错误链上工作。我们将在下一个教程中了解更多相关内容。
出于本教程的目的,如果传递给该函数的两个错误相同,则Is
可以将该函数视为true
然后返回。
Is
第 12 行返回 true 。因为错误是由于格式错误造成的。该程序将打印,
Bad pattern error: syntax error in pattern
标准库使用上述任何一种方法来提供有关错误的更多信息。我们将在下一个教程中使用这些方法来创建我们自己的自定义错误
不要忽视错误
永远不要忽视错误。忽略错误会招致麻烦。让我重写示例,其中列出了与模式匹配的所有文件的名称,忽略错误。
package mainimport ( "fmt""path/filepath"
)func main() { files, _ := filepath.Glob("[")fmt.Println("matched files", files)
}
Run in playground
从前面的例子中我们已经知道是无效的。我通过_
使用空白标识符忽略了函数返回的错误。我只是打印匹配的文件。该程序将打印
matched files []
由于我们忽略了该错误,因此输出看起来好像没有文件与该模式匹配,但实际上该模式本身格式错误。所以永远不要忽视错误。
本教程到此结束。
相关文章:
Go的错误处理
什么是错误? 错误表示程序中发生的任何异常情况。假设我们正在尝试打开一个文件,但该文件在文件系统中不存在。这是一种异常情况,表示为错误。 Go 中的错误是普通的旧值。就像任何其他内置类型(例如 int、float64 等)…...
云原生相关概念
云计算 指托管在外部数据中心并按使用量付费提供给用户的软件基础设施。公司不必为昂贵的服务器付费并进行维护。相反,他们可以使用云提供商提供的按需云原生服务,例如存储、数据库和分析。 云原生 是在 云计算环境 中构建、部署和管理现代应用程序的…...

【JS】this指向
一、this指向的四种规则 1.默认绑定规则 默认指向:指向window 独立调用:指向window 对象指向,比较的是引用地址。 console.log(this window); //true console.log({} {}); //false //函数的独立调用 function test(){console.lo…...

SpringCloud Alibaba Demo(Nacos,OpenFeign,Gatway,Sentinel)
开源地址: ma/springcloud-alibaba-demo 简介 参考:https://www.cnblogs.com/zys2019/p/12682628.html SpringBoot、SpringCloud 、SpringCloud Alibaba 以及各种组件存在版本对应关系。可参考下面 版本对应 项目前期准备 启动nacos. ./startup.c…...

基于nodejs+vue畅听校园点歌系统的设计与实现
目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性:…...

IDEA 设置代码注释模板
功能简介: 每次看别人代码时,面对毫无注释的类,除了头大还是头大, 以下提供了一种代码类注释模板 新建java类的时候,自动增加类注释,养成代码开发好习惯 效果展示: 代码模板: #if (…...

emoji对齐 特殊字符对齐 文本对齐
emoji如何对齐 特殊字符如何对齐 高级文本对齐 问题引出 我们在程序打印输出时,如何我们所输出的字符中包含emoji文本,或者其它特殊的字符文本,则我们的打印对齐效果将出现错位。以下代码复现了这一效果(tips: 马老师…...
Selenium Python 中的动作链
Selenium 是一个用于自动化的独立的基于 Web 的工具。 它是任何人都可以使用的开源工具。 与Python语言结合使用该工具进行测试。 操作链是 Selenium 的基本组成部分,提供了一种管理低级交互的方法,例如按键、鼠标移动、鼠标按钮操作以及与上下文菜单的…...

OceanBase:03-集群部署
目录 一、集群规划 二、配置要求 三、部署前配置 1.配置 limits.conf 2.配置 sysctl.conf 3.关闭防火墙 4.关闭 SELinux 5.创建数据目录,修改文件所有者信息 6.设置无密码 SSH 登录 7.安装jdk 四、解压执行安装 五、集群部署 1.OBD命令行部署 2. OBD白…...
PTA: 矩阵的乘法运算
矩阵的乘法运算 题目输入格式输出格式输入样例输出样例 代码 题目 线性代数中的矩阵可以表示为一个row*column的二维数组,当row和column均为1时,退化为一个数,当row为1时,为一个行向量,当column为1时&…...

4K Video Downloader Pro v4.28.0(视频下载器)
4K Video Downloader Pro是一款专业的视频下载软件,支持从YouTube、Vimeo、Facebook、Instagram、TikTok等主流视频网站下载高质量的4K、HD和普通视频。它的操作流程简单,只需复制视频链接并粘贴到软件中即可开始下载。此外,该软件还提供了多…...
java pdf,word,ppt转图片
pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0…...

map set
目录 一、关联式容器 二、键值对 三、树形结构的关联式容器 3.1 set 3.1.1 set的介绍 3.1.2 set的使用 3.2 multiset 3.2.1 multiset的介绍 3.2.2 multiset的使用 3.3 map 3.3.1 map的介绍 3.3.2 map的使用 …...
Fourier分析导论——第3章——Fourier级数的收敛性(E.M. Stein R. Shakarchi)
第 3 章 Fourier级数的收敛性(Convergence of Fourier Series) The sine and cosine series, by which one can represent an arbitrary function in a given interval, enjoy among other remarkable properties that of being convergent. This property did not escape…...

解决ruoyi-vue部署到域名子路径静态资源404
参考ruoyi前端手册...
游戏引擎中为什么要用四元数表示旋转而不用欧拉角旋转?
个人观点,仅供参考,如有错误可太刺激了 四元数的简单概念和使用 欧拉角通常用于表示一个物体的旋转状态,而不是表示旋转过程。 欧拉角描述的是物体相对于某个参考坐标系的朝向或旋转状态,通常以不同的轴(例如&#x…...

E-Office(泛微OA)前台任意文件读取漏洞复现
简介 泛微E-Office是一款企业级的全流程办公自动化软件,它包括协同办公、文档管理、知识管理、工作流管理等多个模块,涵盖了企业日常工作中的各个环节。在该产品前台登录页存在文件读取漏洞。 officeserver.php文件存在任意文件读取漏洞,通…...
前端小案例 | 喵喵大王立大功 | 一个带便利贴功能的todolist面板
文章目录 📚html📚css📚js🐇stickynote.js🐇todolist.js🐇clock.js 📚html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><m…...
算法训练营第十一天 | 20. 有效的括号、 1047. 删除字符串中的所有相邻重复项、150. 逆波兰表达式求值
目录: 力扣 20. 有效的括号力扣 1047. 删除字符串中的所有相邻重复项力扣 150. 逆波兰表达式求值 问题一、 20. 有效的括号 题目链接:20. 有效的括号 - 力扣(LeetCode) 思路分析: 很多朋友刚开始接触这一类题的时候…...

Python unittest单元测试框架 TestSuite测试套件
TestSuite 测试套件简介 对一个功能的验证往往是需要很多多测试用例,可以把测试用例集合在一起执行,这就产生了测试套件TestSuite 的概念,它是用来组装单个测试用例,规定用例的执行的顺序,而且TestSuite也可以嵌套Tes…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...

逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...

MyBatis中关于缓存的理解
MyBatis缓存 MyBatis系统当中默认定义两级缓存:一级缓存、二级缓存 默认情况下,只有一级缓存开启(sqlSession级别的缓存)二级缓存需要手动开启配置,需要局域namespace级别的缓存 一级缓存(本地缓存&#…...

消息队列系统设计与实践全解析
文章目录 🚀 消息队列系统设计与实践全解析🔍 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡💡 权衡决策框架 1.3 运维复杂度评估🔧 运维成本降低策略 🏗️ 二、典型架构设计2.1 分布式事务最终一致…...

恶补电源:1.电桥
一、元器件的选择 搜索并选择电桥,再multisim中选择FWB,就有各种型号的电桥: 电桥是用来干嘛的呢? 它是一个由四个二极管搭成的“桥梁”形状的电路,用来把交流电(AC)变成直流电(DC)。…...