当前位置: 首页 > news >正文

Go错误包装

在本教程中,我们将了解 Go 中的错误包装以及为什么我们需要错误包装。让我们开始吧。

什么是错误包装?

错误包装是将一个错误封装到另一个错误中的过程。假设我们有一个 Web 服务器,它访问数据库并尝试从数据库中获取记录。如果数据库调用返回错误,我们可以决定是包装该错误还是从 Web 服务发送我们自己的自定义错误。

让我们编写一个小程序来理解这一点。

 1package main23import (4	"errors"5	"fmt"6)78var noRows = errors.New("no rows found")9
10func getRecord() error {
11	return noRows
12}
13
14func webService() error {
15	if err := getRecord(); err != nil {
16		return fmt.Errorf("Error %s when calling DB", err)
17	}
18	return nil
19}
20
21func main() {
22	if err := webService(); err != nil {
23		fmt.Printf("Error: %s when calling webservice\n", err)
24		return
25	}
26	fmt.Println("webservice call successful")
27
28}

Run in playground

在上面的程序中,第 16 行我们发送getRecord函数调用时发生的错误的字符串描述。虽然这实际上看起来像是错误包装,

但事实并非如此。让我们在下一节中了解如何包装错误。

错误包装和 Is 函数

errors包中的Is函数报告链中的任何错误是否与目标匹配。

在本例中,在判断webService()函数是否出错,然后在去获取具体错误的类型,没获取到就返回unknown error when searching record

让我们修改这个程序的函数,并使用该函数检查链中是否有与错误匹配的错误。

 1func main() {2	if err := webService(); err != nil {3		if errors.Is(err, noRows) {4			fmt.Printf("The searched record cannot be found. Error returned from DB is %s", err)5			return6		}7		fmt.Println("unknown error when searching record")8		return9
10	}
11	fmt.Println("webservice call successful")
12
13}

在上面的 main 函数中,第 3行该Is函数将检查保存的错误链中是否有任何错误err包含noRows错误。当前状态下的代码将不起作用,并且if中的条件将不起作用。上面的main函数都会失败。为了使其工作,我们需要noRows在函数返回错误时包装错误webService。一种方法是%w在返回错误时使用格式说明符而不是%s. 因此,如果我们修改返回错误的行

1        return fmt.Errorf("Error %w when calling DB", err)

这意味着新返回的错误包含原始错误noRowsif中的条件。上面main函数就成功了。下面提供了带有错误包装的完整程序。

package mainimport ("errors""fmt"
)var noRows = errors.New("no rows found")func getRecord() error {return noRows
}func webService() error {if err := getRecord(); err != nil {return fmt.Errorf("Error %w when calling DB", err)}return nil
}func main() {if err := webService(); err != nil {if errors.Is(err, noRows) {fmt.Printf("The searched record cannot be found. Error returned from DB is %s", err)return}fmt.Println("unknown error when searching record")return}fmt.Println("webservice call successful")}

Run in playground

当这个程序运行时,它会打印。

The searched record cannot be found. Error returned from DB is Error no rows fou
nd when calling DB

作为函数

error 包中的 As将尝试将作为输入传递的错误转换为目标错误类型。如果错误链中的任何错误与目标匹配,则它将成功。如果成功,它将返回 true,并将目标设置为错误链中匹配的第一个错误。程序会让事情变得更容易理解:)

package mainimport ("errors""fmt"
)type DBError struct {desc string
}func (dbError DBError) Error() string {return dbError.desc
}func getRecord() error {return DBError{desc: "no rows found",}
}func webService() error {if err := getRecord(); err != nil {return fmt.Errorf("Error %w when calling DB", err)}return nil
}func main() {if err := webService(); err != nil {var dbError DBErrorif errors.As(err, &dbError) {fmt.Printf("The searched record cannot be found. Error returned from DB is %s", dbError)return}fmt.Println("unknown error when searching record")return}fmt.Println("webservice call successful")}

Run in playground

在上面的程序中,我们修改了getRecord函数。返回类型的自定义错误

在 main 函数中,我们尝试将webService()函数调用返回的错误转换为DBError. 第32 行if的声明将会成功,因为我们已经在第 24 行包装了DBError从函数返回错误时的错误 webService() 。.运行该程序将打印

The searched record cannot be found. Error returned from DB is no rows found

我们应该包装错误吗?

这个问题的答案是,视情况而定。如果我们包装错误,我们就会将其暴露给库/函数的调用者。我们通常不希望包装包含函数内部实现细节的错误。要记住的一件更重要的事情是,如果我们返回一个包装的错误,然后决定删除错误包装,则使用我们的库的代码将开始失败。因此,包装错误应被视为 API 的一部分,如果我们决定修改返回的错误,则应进行适当的版本更改。

我希望你喜欢这个教程。祝你有美好的一天 :)

相关文章:

  • React18新特性?
  • 【书籍篇】Spring实战第4版 第1部分 Spring的核心
  • 【qemu逃逸】HWS2017-FastCP
  • Paddle炼丹炉炸了Unexpected BUS error encountered in DataLoader worker
  • 计算机网络第4章-网络层(1)
  • 通讯网关软件032——利用CommGate X2OPC实现OPC客户端访问Modbus TCP设备
  • 1,Opencv常用结构
  • ENVI波段合成
  • 多式联运路径优化问题:基于拓扑排序的遗传算法染色体编码
  • Docker之docker-compose(介绍,安装及入门示例)
  • 数据结构与算法超详细笔记(含代码分析)
  • rhcsa-vim
  • Android和JNI交互 : 常见的图像格式转换 : NV21、RGBA、Bitmap等
  • 网络编程——以太网协议
  • DPDK系列之三十五DPDK网络数据发送
  • [原]深入对比数据科学工具箱:Python和R 非结构化数据的结构化
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • 【MySQL经典案例分析】 Waiting for table metadata lock
  • Android系统模拟器绘制实现概述
  • Centos6.8 使用rpm安装mysql5.7
  • CSS实用技巧
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • in typeof instanceof ===这些运算符有什么作用
  • input的行数自动增减
  • java中具有继承关系的类及其对象初始化顺序
  • mac修复ab及siege安装
  • mysql innodb 索引使用指南
  • scala基础语法(二)
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • 探索 JS 中的模块化
  • 移动端高清、多屏适配方案
  • ​ubuntu下安装kvm虚拟机
  • ###C语言程序设计-----C语言学习(3)#
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • (1) caustics\
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (2)MFC+openGL单文档框架glFrame
  • (2)STL算法之元素计数
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (三)mysql_MYSQL(三)
  • (一)Thymeleaf用法——Thymeleaf简介
  • (译) 函数式 JS #1:简介
  • ***测试-HTTP方法
  • .net core使用ef 6
  • .Net IOC框架入门之一 Unity
  • .NET Reactor简单使用教程
  • .net 使用$.ajax实现从前台调用后台方法(包含静态方法和非静态方法调用)
  • .net6使用Sejil可视化日志
  • .NET导入Excel数据
  • .Net下C#针对Excel开发控件汇总(ClosedXML,EPPlus,NPOI)
  • .NET序列化 serializable,反序列化
  • .net用HTML开发怎么调试,如何使用ASP.NET MVC在调试中查看控制器生成的html?
  • .secret勒索病毒数据恢复|金蝶、用友、管家婆、OA、速达、ERP等软件数据库恢复
  • /var/lib/dpkg/lock 锁定问题