位置: IT常识 - 正文

golang中的错误处理(golang eventbus)

编辑:rootadmin
0.1、索引 https://waterflow.link/articles/1666716727236 1、panic 当我们执行panic的时候会结束下面的流程: package main import "fmt" func main() { fmt.Println("hello") panic ... 0.1、索引

推荐整理分享golang中的错误处理(golang eventbus),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:go语言错误处理,golang errors,golang queue,golang errors.new,golang异常处理最佳实践,golang异常处理最佳实践,golang 错误处理,golang 错误处理,内容如对您有帮助,希望把文章链接给更多的朋友!

https://waterflow.link/articles/1666716727236

1、panic

当我们执行panic的时候会结束下面的流程:

package mainimport "fmt"func main() {fmt.Println("hello")panic("stop")fmt.Println("world")}go run 9.gohellopanic: stop

但是panic也是可以捕获的,我们可以使用defer和recover实现:

package mainimport "fmt"func main() {defer func() {if r := recover(); r != nil {fmt.Println("recover: ", r)}}()fmt.Println("hello")panic("stop")fmt.Println("world")}go run 9.gohellorecover: stop

那什么时候适合panic呢?在 Go 中,panic 用于表示真正的异常,例如程序错误。我们经常会在一些内置包里面看到panic的身影。

比如strings.Repeat重复返回一个由字符串 s 的计数副本组成的新字符串:

func Repeat(s string, count int) string {if count == 0 {return ""}// if count < 0 {panic("strings: negative Repeat count")} else if len(s)*count/count != len(s) {panic("strings: Repeat count causes overflow")}...}

我们可以看到当重复的次数小于0或者重复count次之后s的长度溢出,程序会直接panic,而不是返回错误。这时因为strings包限制了error的使用,所以在程序错误时会直接panic。

还有一个例子是关于正则表达式的例子:

package mainimport ("fmt""regexp")func main() {pattern := "a[a-z]b*" // 1compile, err := regexp.Compile(pattern) // 2if err != nil { // 2fmt.Println("compile err: ", err)return} // 3allString := compile.FindAllString("acbcdadb", 3)fmt.Println(allString)}编写一个正则表达式调用Compile,解析正则表达式,如果成功,返回用于匹配文本的 Regexp 对象。否则返回错误利用正则,在输入的字符串中,获取所有的匹配字符

可以看到如果上面正则解析失败是可以继续往下执行的,但是regexp包中还有另外一个方法MustCompile:

func MustCompile(str string) *Regexp {regexp, err := Compile(str)if err != nil {panic(`regexp: Compile(` + quote(str) + `): ` + err.Error())}return regexp}

这个方法说明正则的解析是强依赖的,如果解析错误,直接panic结束程序。用户可以根据实际情况选择。

但是实际开发中我们还是要谨慎使用panic,因为它会使程序结束运行(除非我们调用defer recover)

2、包装错误golang中的错误处理(golang eventbus)

错误包装是将错误包装或者打包在一个包装容器中,这样的话我们就可以追溯到源错误。错误包装的主要作用就是:

为错误添加上下文将错误标记为特定类型的错误

我们可以看一个访问数据库的例子:

package mainimport ("fmt""github.com/pkg/errors")type Courseware struct {Id int64Code stringName string}func getCourseware(id int64) (*Courseware, error) {courseware, err := getFromDB(id)if err != nil {return nil, errors.Wrap(err, "六月的想访问这个课件") // 2}return courseware, nil}func getFromDB(id int64) (*Courseware, error) {return nil, errors.New("permission denied") // 1}func main() {_, err := getCourseware(11)if err != nil {fmt.Println(err)}}访问数据库时我们返回了原始的错误信息到上层我们添加了一些自定义的上下文信息go run 9.go六月的想访问这个课件: permission denied

当然我们也可以将错误包装成我们自定义类型的错误,我们稍微修改下上面的例子:

package mainimport ("fmt""github.com/pkg/errors")type Courseware struct {Id int64Code stringName string}// 1type ForbiddenError struct {Err error}// 2func (e *ForbiddenError) Error() string {return "Forbidden: " + e.Err.Error()}func getCourseware(id int64) (*Courseware, error) {courseware, err := getFromDB(id)if err != nil {return nil, &ForbiddenError{err} // 4}return courseware, nil}func getFromDB(id int64) (*Courseware, error) {return nil, errors.New("permission denied") // 3}func main() {_, err := getCourseware(11)if err != nil {fmt.Println(err)}}首先我们自定义了ForbiddenError的错误类型我们实现了error接口访问数据库抛出原始错误上层返回ForbiddenError类型的错误go run 9.goForbidden: permission denied

当然我们也可以不用创建自定义错误的类型,去包装错误添加上下文:

package mainimport ("fmt""github.com/pkg/errors")type Courseware struct {Id int64Code stringName string}func getCourseware(id int64) (*Courseware, error) {courseware, err := getFromDB(id)if err != nil {return nil, fmt.Errorf("another wrap err: %w", err) // 1}return courseware, nil}func getFromDB(id int64) (*Courseware, error) {return nil, errors.New("permission denied")}func main() {_, err := getCourseware(11)if err != nil {fmt.Println(err)}}使用%w包装错误

使用这的好处是我们可以追溯到源错误,从而方便我们做一些特殊的处理。

还有一种方式是使用:

return nil, fmt.Errorf("another wrap err: %v", err)

%v的方式不会包装错误,所以无法追溯到源错误,但往往有时候我们会选择这种方式,而不用%w的方式。%w的方式虽然能包装源错误,但往往我们会通过源错误去做一些处理,假如源错误被修改,那包装这个源错误的相关错误都需要做响应变化。

3、错误类型判断

我们扩展一下上面查询课件的例子。现在我们有这样的判断,如果传进来的id不合法我们返回400错误,如果查询数据库报错我们返回500错误,我们可以像下面这样写:

package mainimport ("fmt""github.com/pkg/errors")type Courseware struct {Id int64Code stringName string}type ForbiddenError struct {Err error}func (e *ForbiddenError) Error() string {return "Forbidden: " + e.Err.Error()}func getCourseware(id int64) (*Courseware, error) {if id <= 0 {return nil, fmt.Errorf("invalid id: %d", id)}courseware, err := getFromDB(id)if err != nil {return nil, &ForbiddenError{err}}return courseware, nil}func getFromDB(id int64) (*Courseware, error) {return nil, errors.New("permission denied")}func main() {_, err := getCourseware(500) // 我们可以修改这里的id看下打印的结构if err != nil {switch err := err.(type) {case *ForbiddenError:fmt.Println("500 err: ", err)default:fmt.Println("400 err: ", err)}}}go run 9.go500 err: Forbidden: permission denied

这样看起来好像也没什么问题,现在我们稍微修改下代码,把上面ForbiddenError包装一下:

package mainimport ("fmt""github.com/pkg/errors")type Courseware struct {Id int64Code stringName string}type ForbiddenError struct {Err error}func (e *ForbiddenError) Error() string {return "Forbidden: " + e.Err.Error()}func getCourseware(id int64) (*Courseware, error) {if id <= 0 {return nil, fmt.Errorf("invalid id: %d", id)}courseware, err := getFromDB(id)if err != nil {return nil, fmt.Errorf("wrap err: %w", &ForbiddenError{err}) // 这里包装了一层错误}return courseware, nil}func getFromDB(id int64) (*Courseware, error) {return nil, errors.New("permission denied")}func main() {_, err := getCourseware(500)if err != nil {switch err := err.(type) {case *ForbiddenError:fmt.Println("500 err: ", err)default:fmt.Println("400 err: ", err)}}}go run 9.go400 err: wrap err: Forbidden: permission denied

可以看到我们的Forbidden错误进到了400里面,这并不是我们想要的结果。之所以会这样,是因为在ForbiddenError的外面又包装了一层Error错误,使用类型断言的时候判断出来的是Error错误,所以进到了400分支。

这里我们可以使用errors.As方法,它会递归调用Unwrap方法,找到错误链中第一个与target匹配的方法:

package mainimport ("fmt""github.com/pkg/errors")type Courseware struct {Id int64Code stringName string}type ForbiddenError struct {Err error}func (e *ForbiddenError) Error() string {return "Forbidden: " + e.Err.Error()}func getCourseware(id int64) (*Courseware, error) {if id <= 0 {return nil, fmt.Errorf("invalid id: %d", id)}courseware, err := getFromDB(id)if err != nil {return nil, fmt.Errorf("wrap err: %w", &ForbiddenError{err})}return courseware, nil}func getFromDB(id int64) (*Courseware, error) {return nil, errors.New("permission denied")}func main() {_, err := getCourseware(500)if err != nil {var f *ForbiddenError // 这里实现了*ForbiddenError接口,不然会panicif errors.As(err, &f) { // 找到匹配的错误fmt.Println("500 err: ", err)} else {fmt.Println("400 err: ", err)}}}go run 9.go500 err: wrap err: Forbidden: permission denied4、错误值判断

在代码中或者mysql库或者io库中我们经常会看到这样的全局错误:

var ErrCourseware = errors.New("courseware")

这种错误我们称之为哨兵错误。一般数据库没查到ErrNoRows或者io读到了EOF错误,这些特定的错误可以帮助我们做一些特殊的处理。

一般我们会直接用==号判断错误值,但是就像上面的如果错误被包装哪我们就不好去判断了。好在errors包中提供了errors.Is方法,通过递归调用Unwrap判断错误链中是否与目标错误相匹配的错误值:

if err != nil { if errors.Is(err, ErrCourseware) { // ... } else { // ... }}
本文链接地址:https://www.jiuchutong.com/zhishi/310534.html 转载请保留说明!

上一篇:python变量中self的添加(Python变量中forain)

下一篇:Python之字典遍历元素(4种方式)(python字典遍历key)

  • 抖音可以绑定银行卡吗(抖音可以绑定银行卡可以解绑吗)

    抖音可以绑定银行卡吗(抖音可以绑定银行卡可以解绑吗)

  • 火狐浏览器兼容模式怎么设置(火狐浏览器兼容性选项在哪)

    火狐浏览器兼容模式怎么设置(火狐浏览器兼容性选项在哪)

  • 手机如何绑定银行卡(手机如何绑定银行卡的步骤)

    手机如何绑定银行卡(手机如何绑定银行卡的步骤)

  • 抖音作者回复怎么置顶(抖音作者回复怎么删除)

    抖音作者回复怎么置顶(抖音作者回复怎么删除)

  • 华为mate10文件管理在哪里(华为mate10文件夹在哪)

    华为mate10文件管理在哪里(华为mate10文件夹在哪)

  • ipadpro2020是第几代(ipadpro2021是第几代pro)

    ipadpro2020是第几代(ipadpro2021是第几代pro)

  • 小米手环5什么上市时间(小米手环5什么时候充电比较好)

    小米手环5什么上市时间(小米手环5什么时候充电比较好)

  • 怎样看抖音点赞的人(怎样看抖音点赞的是谁)

    怎样看抖音点赞的人(怎样看抖音点赞的是谁)

  • rx580series什么版本(rx580几个版本)

    rx580series什么版本(rx580几个版本)

  • dvi和hdmi区别(dvi和hdmi画质差别大吗)

    dvi和hdmi区别(dvi和hdmi画质差别大吗)

  • 平板保修期多久(华为平板保修期多久)

    平板保修期多久(华为平板保修期多久)

  • 数据库和文件系统的区别(数据库和文件系统一样吗)

    数据库和文件系统的区别(数据库和文件系统一样吗)

  • 电脑ie系列浏览器有哪些(电脑ie系列浏览器怎么用)

    电脑ie系列浏览器有哪些(电脑ie系列浏览器怎么用)

  • iphone7有3dtouch吗(苹果7有没有3d)

    iphone7有3dtouch吗(苹果7有没有3d)

  • wps文档怎么搜索关键字(wps文档怎么搜索关键词)

    wps文档怎么搜索关键字(wps文档怎么搜索关键词)

  • 手机微信如何发送邮箱(手机微信如何发邮箱给别人)

    手机微信如何发送邮箱(手机微信如何发邮箱给别人)

  • oppoa11x怎么开启护眼模式(OPPOA11X怎么开启手机定位)

    oppoa11x怎么开启护眼模式(OPPOA11X怎么开启手机定位)

  • airpods2容易掉吗(airpods2容易脱落吗)

    airpods2容易掉吗(airpods2容易脱落吗)

  • 腾讯视频投屏连接失败(腾讯视频投屏连不上)

    腾讯视频投屏连接失败(腾讯视频投屏连不上)

  • PS怎么处理全景照片的尺寸(ps怎么处理全景图)

    PS怎么处理全景照片的尺寸(ps怎么处理全景图)

  • 华为3d建模怎么打开(华为3D建模怎么用)

    华为3d建模怎么打开(华为3D建模怎么用)

  • oppok3新机发布时间(oppok3的发布时间)

    oppok3新机发布时间(oppok3的发布时间)

  • 4g限速后怎样提升网速(4g限速后怎样提升速度)

    4g限速后怎样提升网速(4g限速后怎样提升速度)

  • 手机怎么散热快(华为手机怎么散热快)

    手机怎么散热快(华为手机怎么散热快)

  • searchnavversion.exe - searchnavversion是什么进程  作用是什么

    searchnavversion.exe - searchnavversion是什么进程 作用是什么

  • 让Mac屏幕横向或翻转显示适合躺在床上看电子书(mac屏幕横过来了)

    让Mac屏幕横向或翻转显示适合躺在床上看电子书(mac屏幕横过来了)

  • HTML+CSS+JavaScript仿京东购物商城网站 web前端制作服装购物商城 html电商购物网站

    HTML+CSS+JavaScript仿京东购物商城网站 web前端制作服装购物商城 html电商购物网站

  • 筹建期的收入要交企业所得税吗
  • 减免所得税额是怎么算出来的12行
  • 微信企业版支付
  • 股东继续投资
  • 公司购买食品如何入账
  • 会计哪些账本需要保存
  • 出口退税网上服务中心app
  • 认证不抵扣的账务处理
  • 公司购买厂房需要交房产税吗
  • 委托开发费用免所得税和增值税
  • 个体工商户所得税税率表
  • 电子商务支付平台有哪些
  • 技术服务行业分析
  • 企业收取多年租金怎么算
  • 被辞退还有退休金吗
  • 残疾人收到房租租赁发票收入还要缴纳个税吗
  • 哪些情况下小型车不能走
  • 长期待摊费忘记摊了怎么办
  • 哪些资产减值损失可以 转回,哪些不能?
  • 返修产品如何账务处理
  • 技术合同的计税依据包括研究开发经费
  • 鸿蒙系统开发人员选项
  • 主营业务收入科目应按什么进行明细核算
  • 销售返点怎么做分录
  • 自来水公司的水压力是多少
  • vim diff对比
  • scheduler.exe - scheduler是什么进程 有何作用
  • 当前页面的脚本发生错误代码0没有注册类
  • 企业合并收购,对员工的机会和挑战
  • 补充协议是否缴纳印花税
  • .ico是什么文件
  • 二手房交易土增税文件
  • php rewind
  • php 生成opcode
  • vue3props用法
  • 信用减值损失属于损益类科目吗
  • 投喂小鸟
  • 怎么让gridview居中
  • chat form
  • SSD目标检测算法
  • centos7配置自动获取ip
  • css设置渐变色背景
  • 简易计税适用什么类型企业
  • 长期借款科目的借方反映的内容
  • 试生产产品计入研发费用吗
  • 织梦怎么用模板建站
  • github+hexo搭建博客
  • 银行进账单是外来原始凭证吗
  • 揭秘如何投屏纽约时代广场
  • 充电桩的安装费是多少
  • 怎么计算城市
  • 会计利润调增调减项目
  • 物业公司代收取暖费怎么缴纳税额
  • 运输费和货款一样吗
  • 租金摊销会计分录
  • 跨年跨月发票账务处理
  • 个税公司少申报一个月会对个人有什么影响
  • 股东股权转让印花税 公司承担
  • 购入自用的机器怎么入账
  • 支付银行手续费等直接收费金融服务
  • 赠送客户的商品怎么入账
  • sql server 数据库介绍
  • xp系统c盘到底哪些文件可以删除越详细越好谢谢
  • debian linux教程
  • 无线和网络飞行模式
  • jquery ajaxfileupload异步上传插件
  • Unity3D游戏开发标准教程
  • 使用的拼音
  • 超级硬盘数据恢复软件v2.7
  • linux版本控制软件
  • linux sleep 2
  • 批处理查找字符中含有等号的子串
  • 提高你工作效率的方法
  • js键盘事件有哪些?各自的作用如何
  • unity3d颜色
  • python语句查询
  • 天津税务局怎么申报社保
  • 一般纳税人企业所得税怎么征收
  • 代扣代缴企业所得税手续费
  • 转租土地合法吗现在
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设