当前位置: 首页 > 后端技术 > PHP

厉害了,,,Goerrorhandling中的宝贝能解决麻烦吗?

时间:2023-03-29 23:39:02 PHP

大家好,我是炸鱼。在Go编程中,总是讨论错误处理机制的处理。但是Go1也无能为力,那就想办法继续优化吧。今天建宇就给大家介绍一下我在五一假期学习时看到的一个新提案。背景在这个阶段,我们可以在标准库中包装错误的唯一方法是使用fmt.Errorf,它相对较小,易于操作。这意味着我们对错误所能做的就是将错误内容添加到它的.Error()输出中,从而声明一个error类型的值。代码如下:err:=fmt.Errorf("Friedfish:%s",errors.New("Onholiday"))iferr!=nil{}但是业务需求往往没有那么简单。这时候如果我们想在收到错误信息的时候返回栈并提供其他信息(例如:业务状态码),没有特别简单的方法。很难做到,只有3个选项:你可以返回一个新的其他错误,但你会丢失原始错误的上下文信息。您可以使用fmt.Errorf包装错误,这只会添加文本输出,而不是调用者可以通过编程方式检查的内容。您可以编写包含要检查的元数据的复杂错误包装器结构,使用error.Is、.As和.Unwrap以允许调用者访问错误的根本原因。现在最靠谱的是第三种方法,最全,对应Go1.13新增的错误系列方法,目前还处于青壮年阶段(多年来唯一新的错误处理完成)。提案原作者认为现阶段还不够简单方便。新提案新提案是在标准库错误中实现一个更简单的函数来实现上面第3点的效果,以支持将任何错误与任何其他错误一起包装,以便它们形成一个新的包装错误列表。以下代码://With返回一个用other包装err的错误。funcWith(err,othererror)error这个包裹的error类似于链表,可以复用errors.Unwrap遍历链表。而类链表存储,存在顺序问题。在With函数中,其他参数的错误将放在包装错误列表的头部。如果调用With函数时是With(b->a,d->c),则呈现的错误列表为:d->c->b->a。对应的使用场景:errors.Is(errors.With(err,other)):criterion:errors.Is(other)||错误。是(错误)。errors.As(errors.With(err,other),target):条件:errors.As(other,target)||errors.As(err,target)errors.With(err,other).Error():输出为other.Error()+":"+err.Error()。提案作者@NateFinch希望通过这种错误打包方式,对现有代码的改动最小。提供最广泛的功能适用性也被认为是有价值的。CaseScenario作者给出了一个非常经典的用户案例。当我们编写应用程序代码时,我们会在我们编写的每个Go应用程序中看到它。应用程序中有一个包会返回特定于域的错误,例如返回pq.ErrNoRows的postgres驱动程序。您希望将错误向上传递到堆栈以维护原始错误的上下文,但您不希望调用者必须了解postgres错误才能知道如何从存储层处理它。Retrofit可以使用新的With函数,并且您可以通过众所周知的错误类型添加元数据,以便可以一致地检查您的函数返回的错误,而不管底层实现如何。以下代码://SetUserName设置具有给定ID的用户的名称。//如果找不到用户,则此方法返回flags.NotFound;如果具有该名称的用户//已存在,则返回flags.Conflict。func(st*Storage)SetUserName(iduuid.UUID,namestring)error{err:=st.db.SetUser(id,"name="+name)iferrors.Is(err,pq.ErrNoRows){返回nil,错误。With(err,flags.NotFound)}varpqErr*pq.Erroriferrors.As(err,&pqErr)&&pqErr.Constraint=="unique_user_name"{返回错误.With(err,flags.Conflict)}iferr!=nil{//其他一些未知错误returnfmt.Errorf("errorsettingnameonuserwithid%v:%w",err)}returnnil}这种错误通常称为哨兵错误。综上所述,今天给大家介绍的方案,更适合我们日常工作中的使用场景。平时写Go应用想的很多,就会折腾这个问题。会出现,是否需要根据错误文本来判断错误内容?所以,比如业界的错误库,或者毛老师之前说的,都会进行相关的设计。这个提议也是一个很好的补充。文章持续更新中。可以微信搜索【脑补炸鱼】阅读。本文已收录在GitHubgithub.com/eddycjy/blog中。学习Go语言可以看Go学习地图和路线。欢迎星星提醒。推荐阅读Go语言入门系列:初探Go项目实战Go语言编程之旅:深入使用Go作为项目Go语言设计哲学:理解Go的Why与设计思维Go语言进阶之旅:进一步深入Go源码Go讨论13年,如何解决重赋值的坑?10+围棋官方谚语,你知道几个?参考提案内容来自《proposal: errors: Add With(err, other error) error》