品牌 资讯 搭配 材料 时尚 热点 行业 首饰 玉石 行情

头条:GO 1.20 新功能:多重错误包装

2022-12-27 14:14:58 来源:

预计将于 2023 年 2 月发布的 Go 1.20 有一个小的变化,对于那些大量使用错误包装的应用程序来说,可能会有效改进它们的错误处理方法。


(资料图片)

让我们看一下它的用法,但首先,需要简要回顾一下什么是错误包装。如果你已经掌握了可以直接跳到下面的 “Go 1.20 新功能” 部分以获取新的信息。

Go 中的错误是实现一个非常简单的接口:

typeerrorinterface{Error()string}

错误类型可以是任何东西,从string本身到int,但通常它们是struct类型。下面这个例子来自标准库:

typeerrstruct{sstring}func(e*err)Error()string{returne.s}

要检查 Go 中的错误,你只需比较一个值(在本例中为int值):

iferr==io.EOF{//...}

第二种常见的用法是检查错误的类型,那也意味着要写更多的代码:

ifnerr,ok:=err.(net.Error){//...(usenerrwhichisanet.Error)}

在上面的例子中,类型断言测试类型net.Error的err值,并创建一个新变量nerr,它可以在 if 语句中使用。Go 中的错误方便理解、易于使用且非常高效。

错误包装

从 Go 1.13 开始,引入了错误包装。包装允许将错误嵌入到其他错误中,就像在其他语言中包装异常一样。这非常实用,比如函数遇到 “record not found” 错误时,可以向错误信息中添加更多上下文信息,例如 “unknown user: record not found”。

Go 中错误包装设计背后的有趣想法是:契约不用关心错误类型、结构或它们是如何创建的。而唯一关注的是解包过程和转换为字符串,因为这两者是必须的。这就非常容易实现:支持解包的错误类型必须实现Unwrap() error方法。

标准库中没有(命名的)接口可以向您展示,因为接口是隐式实现的,没有必要单独写一个。这里我们写一个只是为了更好说明这篇文章:

typeWrappedErrorinterface{Unwrap()error}

我们来看看 Go 标准库(实际上是 package fmt)中是如何实现包装错误的:

typewrapErrorstruct{msgstringerrerror}func(e*wrapError)Error()string{returne.msg}func(e*wrapError)Unwrap()error{returne.err}

由于上面错误类型实现了Error() string方法,所以说 Go 中的错误实际上最终是字符串并没有错,因此需要一种创建这些字符串的良好机制。这就是标准库中的函数fmt.Errorf发挥作用的地方:

varRecordNotFoundErr=errors.New("notfound")constname,id="lzap",13werr:=fmt.Errorf("unknownuser%q(id%d):%w",name,id,recordNotFoundErr)fmt.Println(werr.Error())

一个特殊格式的动词%w,每次调用只能使用一次(稍后会详细介绍),用于错误参数。除此之外,该函数的工作方式类似于fmt.Printf函数。下面的例子打印了这个结果:

unknownuser"lzap"(id13):notfound

如你所见,错误包装本质上是一个链表。要解包错误,请使用errors.Unwrap函数,该函数将为链表中的最后一个错误值返回nil。要检查错误类型或值,需要遍历整个列表,这对于需要进行频繁的错误检查不太实用。幸运的是,有两个辅助函数可以做到这一点。

检查包装错误列表中的值:

iferrors.Is(err,RecordNotFoundErr){//...}

检查特定类型(下面例子是来自标准库的网络错误):

varnerr*net.Erroriferrors.As(err,&nerr){//...(usenerrwhichisa*net.Error)}

以上总结了 Go 1.13 及更高版本中的错误包装。

Go 1.20 新特性

让我们看看 Go 1.20 中真正的新功能,从函数errors.Join开始,它通过可变参数包装错误列表:

err1:=errors.New("err1")err2:=errors.New("err2")err:=errors.Join(err1,err2)fmt.Println(err)

当事先不知道错误数量时,此功能可用于将错误连接在一起。一个很好的例子是从 goroutines 收集错误。值得一提的是,该函数将列表中的错误与换行符连接起来。上面的代码片段打印:

err1err2

对于许多应用程序或(日志记录)库来说,这可能会存在问题,它们期望错误通常只是没有换行符的字符串。幸运的是,Go 1.20 中的另一个变化改变了fmt.Errorf的行为:该函数现在接受多个%w格式说明符:

err1:=errors.New("err1")err2:=errors.New("err2")err:=fmt.Errorf("%w+%w",err1,err2)fmt.Println(err)

以前会导致格式错误的格式字符串现在可以正确打印:

err1+err2

同时包装多个错误实现Unwrap() error,这是可能的吗?

事实证明,在 Go 1.20 标准库中有一种新的机制: 实现Unwrap() []error函数的错误类型可以包装多个错误。让我们来看看这是如何在库中实现的:

typejoinErrorstruct{errs[]error}func(e*joinError)Error()string{//concatenateerrorswithanewlinecharacter}func(e*joinError)Unwrap()[]error{returne.errs}

一个理论上的接口,但标准库中实际不存在,如下所示:

typeMultiWrappedErrorinterface{Unwrap()[]error}

由于 Go 不允许方法重载,因此每种类型都可以实现Unwrap() error或Unwrap() []error,但不能同时实现。还记得我提到过包装错误本质上是一个链表吗?实现前一个(新引入的)方法的类型实际上形成了一个链接树,函数errors.Is和errors.As的工作方式相同,只是现在它们需要遍历树而不是列表。根据文档,该实现执行预排序、深度优先遍历。

这确实是 Go 1.20 带来的全部,它可能看起来是一个小的变化,但它提供了如何有效和干净地处理错误的新方法。在展示真实示例之前,让我总结一下新功能:

新的Unwrap []error函数契约允许遍历错误树。

新的errors.Join函数,这是一个方便的函数,用于连接两个错误字符串值(使用换行符)。

现有函数errors.Is和errors.As已更新,可以同时处理错误列表和错误树。

现有函数fmt.Errorf现在接受多个%w格式动词。实践

上面这一切都很棒,但是你如何在实践中利用它呢?

在一个小型 REST API 微服务中,我们通过errors.New和fmt.Errorf处理来自 DAO 包(数据库)、REST 客户端(其他后端服务)和其他包的各种错误。返回的 HTTP 状态代码应该是 2xx、4xx 或 5xx,具体取决于错误状态以遵循最佳 REST API 实践。实现此过程的一种方法是解开主 HTTP 处理程序中的错误并找出它是哪种错误。

然而,通过多重错误包装,现在可以包装根本原因(例如数据库返回 “no records found” )和返回给用户 HTTP 代码(在本例中为 404)。

一个工作示例如下所示:

packagemainimport("errors""fmt")//commonHTTPstatuscodesvarNotFoundHTTPCode=errors.New("404")varUnauthorizedHTTPCode=errors.New("401")//databaseerrorsvarRecordNotFoundErr=errors.New("DB:recordnotfound")varAffectedRecordsMismatchErr=errors.New("DB:affectedrecordsmismatch")//HTTPclienterrorsvarResourceNotFoundErr=errors.New("HTTPclient:resourcenotfound")varResourceUnauthorizedErr=errors.New("HTTPclient:unauthorized")//applicationerrors(thenewfeature)varUserNotFoundErr=fmt.Errorf("usernotfound:%w(%w)",RecordNotFoundErr,NotFoundHTTPCode)varOtherResourceUnauthorizedErr=fmt.Errorf("unauthorizedcall:%w(%w)",ResourceUnauthorizedErr,UnauthorizedHTTPCode)funchandleError(errerror){iferrors.Is(err,NotFoundHTTPCode){fmt.Println("Willreturn404")}elseiferrors.Is(err,UnauthorizedHTTPCode){fmt.Println("Willreturn401")}else{fmt.Println("Willreturn500")}fmt.Println(err.Error())}funcmain(){handleError(UserNotFoundErr)handleError(OtherResourceUnauthorizedErr)}

这将打印:

Willreturn404usernotfound:DB:recordnotfound(404)Willreturn401unauthorizedtocallotherservice:HTTPclient:unauthorized(401)

从这样的人工代码片段中可能看起来不太明显的是,实际上的错误声明通常分布在许多包中,并且不容易跟踪所有可能的错误以确保所需的 HTTP 状态代码。在这种方法中,所有在一个地方声明的应用程序级包装错误也包含了 HTTP 代码。

请注意,这在 Go 1.19 或更早版本中是不可能的,因为fmt.Errorf函数只会包装第一个错误。该代码确实在 1.19 上可以编译,甚至不会产生运行时恐慌,但它实际上不会工作。

显然,常见的 HTTP 状态代码很容易成为一种新的错误类型(基于int类型),因此可以通过errors.As轻松提取实际代码,但我想让示例保持简单。

Feel free to play around with the code on Go Playground. Make sure to use “dev branch” or 1.20+ version of Go. 可以在 Go Playground 上自由运行上述代码。确保使用 “dev branch” 或 Go 的 1.20+ 版本。现有应用

在你的应用程序中实施新功能时,请注意errors.Unwrap函数。对于具有Unwrap() []error的错误类型,它总是返回nil:

err1:=errors.New("err1")err2:=errors.New("err2")err:=errors.Join(err1,err2)unwrapped:=errors.Unwrap(err)fmt.Println(unwrapped)

由于 Go 1.X 兼容性承诺,这会打印出 “nil”。当你引入多个包装错误时,请确保检查展开代码。幸运的是,典型 Go 代码中的大部分错误检查都是使用errors.Is和errors.As完成的。

错误包装并不是 Go 中所有错误处理的最终解决方案。它只是提供了一种干净的方法来处理典型 Go 应用程序中的错误,对于简单应用程序来说也许就完全足够了。原文地址:https://lukas.zapletalovi.com/posts/2022/wrapping-multiple-errors/原文作者:Lukáš Zapletal本文永久链接:https://github.com/gocn/translator/blob/master/2022/w50_Wrapping_multiple_errors译者:haoheipi

校对:watermelo

往期推荐

谷歌发布查找开源漏洞的Go工具OSV-Scanner

最好的Go框架:没有框架?

「每周译Go」如何在Go中构造For 循环

想要了解Go更多内容,欢迎扫描下方关注公众号,回复关键词 [实战群],就有机会进群和我们进行交流

分享、在看与点赞Go

标签:

(责任编辑:)

相关文章

头条:GO 1.20 新功能:多重错误包装

​预计将于2023年2月发布的Go1 20有一个小的变化,对于那些大量使用错误包装的应用程序来说,可能会有效改进它们的错误处理方法。让我们看一下它的

2022-12-27 14:14:58

《诗画中国》浪漫收官诗画合璧展现大美中华

​中央广播电视总台大型文化节目《诗画中国》上周已迎来收官。节目以“诗画合璧”的全新样态和新颖视角,深化“思想+艺术+技术”的融合传播,...

2022-12-27 08:55:28

康缘药业24小时满负荷生产抗疫产品,散寒化湿颗粒最高扩产至70多万袋

​多个产品被国家及各省新冠防治方案所推荐的康缘药业(600557 SH),正在扩产。  “公司的散寒化湿颗粒之前的产能就十几万袋,现在每天提高到

2022-12-26 20:20:45

世界简讯:12月26日梦洁股份涨停分析:网红,纺织服装,流感/口罩概念热股

​梦洁股份涨停收盘,收盘价4 76元。该股于10点28分涨停,未打开涨停,截止收盘封单资金为1626 97万元,占其流通市值0 62%。

2022-12-26 15:17:17

当前简讯:异动快报:麦趣尔(002719)12月26日9点30分触及涨停板

​12月26日盘中消息,9点30分麦趣尔(002719)触及涨停板。目前价格11 42,上涨10 02%。其所属行业饮料乳品目前上涨。领涨股为麦趣尔。该股为大农业

2022-12-26 10:16:01

深圳地铁行车间隔时间调整 早晚高峰期行车间隔调整至6-8分钟 滚动

​证券时报网讯,据深圳地铁消息,根据人员配置情况,自12月26日起,深圳地铁线网(不含4号线)早晚高峰期行车间隔将调整为6-8分钟,非高峰期行

2022-12-25 19:10:54

环球视点!小贝儿子融入豪门!陪岳父抽雪茄,晒圣诞聚餐照,与妮可拉腻歪

​当地时间12月23日,贝克汉姆的大儿子布鲁克林更新了一组近照,这是他在岳父家的圣诞聚餐合影,与妻子妮可拉的亲人们一起吃饭玩乐的温馨瞬间,

2022-12-25 01:31:49

安恒信息(688023)12月23日主力资金净买入1225.41万元 环球热文

​截至2022年12月23日收盘,安恒信息(688023)报收于186 35元,上涨1 31%,换手率0 73%,成交量5756 55手,成交额1 08亿元。12

2022-12-24 08:01:17

天银机电: 关于召开2023年第一次临时股东大会的通知

​天银机电:关于召开2023年第一次临时股东大会的通知

2022-12-23 17:49:44

金山云拟以介绍形式上市 不发股融资-环球报道

​12月23日,中国头部云厂商金山云在香港交易所(HKEX)官网披露上市文件,拟通过介绍上市于12月30日登陆香港主板,不发股融资,对以往股份不造成

2022-12-23 12:56:30

今世缘(603369)12月22日主力资金净卖出940.82万元

​截至2022年12月22日收盘,今世缘(603369)报收于49 72元,上涨2 07%,换手率0 82%,成交量10 26万手,成交额5 16亿元。12月22

2022-12-23 07:29:30

双非本科到大厂,贫困家庭到深圳买房,我的逆袭之路 环球关注

​20岁的你是否在拼命努力的奋斗呢?人这一生,其实大大小小有很多的节点,每个年纪该干每个年纪的事情,一步一步的朝前走下去,应该是大部分人

2022-12-22 18:05:08

世界快讯:上班族备考注册会计师两年时间可以考过吗

​上班族备考注册会计师两年时间考的过,前提是看你报考了几门科目,如果报考的是专业阶段1-4门,上班族备考在两年内的时间还是可以考过的,但报

2022-12-22 12:26:53

每日视讯:“民声直通车”解决群众急难问题

​务川“民声直通车”解决群众急难问题本报讯(通讯员申勇)今年以来,务川自治县信访局创新推行“民声直通车”便民服务,深入拓展民声民意表...

2022-12-22 05:05:34

祥鑫科技(002965.SZ)拟不超2亿元在厦门投建储能金属结构件研发中心及制造基地

​智通财经APP讯,祥鑫科技公告,公司拟在福建省厦门市以自筹资金不超过2亿元投资建设“祥鑫科技(厦门)储能金属结构件研发中心及制造基地项目...

2022-12-21 16:46:21

焦点报道:监管部门连续出手!92起哄抬药价行为迅速结案

​市场监管总局20日召开专题新闻发布会,介绍涉疫药品和医疗用品稳价格保质量有关情况。国家药监局副局长黄果表示,我国布洛芬和对乙酰氨基酚的

2022-12-21 10:45:23

热门:12月20日基金净值:广发安宏回报混合A最新净值1.1044,跌1.43%

​12月20日,广发安宏回报混合A最新单位净值为1 1044元,累计净值为1 4221元,较前一交易日下跌1 43%。历史数据显示该基金近1个月上涨0 16%,近

2022-12-21 01:13:03

中盐化工(600328.SH):拟以1600万元对胡杨矿业进行增资 报资讯

​格隆汇12月20日丨中盐化工(600328 SH)公布,根据公司战略规划,为满足鄂托克旗胡杨矿业有限责任公司业务发展的需要,更好地发挥其原材料保障基

2022-12-20 15:32:33

车e贷逾期7年多久会上征信系统|天天热点

​网贷逾期一般会上征信,有些借贷机构在用户逾期后一天后就会上报给征信机构,而有些借贷机构则是会在几天后上报给征信机构,因为有些借贷机构可

2022-12-20 10:43:08

天天热消息:煌上煌拟定增募资不超4.5亿元

​煌上煌披露非公开发行股票预案。本次发行对象为公司实际控制人徐桂芬家族控制的企业新余煌上煌投资管理中心(有限合伙),发行价格为10 09元 股

2022-12-19 21:04:08

王鸿薇:苏贞昌仍安居高位 民进党有改革?

​中国国民党嘉义市长黄敏惠昨击败民主进步党李俊俋,顺利连任并为国民党再攻下一城。国民党台北市第三选区“立委”补选候选人王鸿薇表示,看...

2022-12-19 15:33:24

天天观点:小赢卡贷贷款被查后多久会上征信

​网贷逾期一般会上征信,有些借贷机构在用户逾期后一天后就会上报给征信机构,而有些借贷机构则是会在几天后上报给征信机构,因为有些借贷机构可

2022-12-19 09:22:17

当前热文:建安区:星级农场为乡村振兴插上腾飞翅膀(二)

​作为全省乡村振兴示范引领县(区),近年来,建安区坚持把产业发展作为乡村振兴的关键点和突破口,积极探索实施现代农场星级管理,培育一批地

2022-12-19 00:12:29

【大美中国】黄海之滨 万鸟翔集

​北京林业大学的科研人员在条子泥湿地筛洗采集的泥样。本报记者周梦爽摄“鹬蚌相争”在条子泥上演。孙家录摄采蛤归来,满载而归的渔民。孙家...

2022-12-18 11:22:25

广东首个“中国服装电商创新示范基地”虎门揭牌

​广东首个“中国服装电商创新示范基地”虎门揭牌。图为揭牌仪式作者李纯中新网广东新闻12月2日电(李映民李纯)广东省首个“中国服装电商创新...

2022-12-17 12:29:11

黄金技术面即将形成“金叉”!分析师:若突破这一关键均线 金价恐大涨向1800美元

​指股网讯周五(12月16日)欧市早盘,现货黄金维持日内反弹走势,金价现报1781美元 盎司附近。知名财经网站FXStreet分析师DhwaniMehta最新撰文,

2022-12-16 21:50:58

本周盘点(12.12-12.16):瑞茂通周涨0.81%,主力资金合计净流出915.51万元

​截至2022年12月16日收盘,瑞茂通(600180)报收于6 26元,较上周的6 21元上涨0 81%。本周,瑞茂通12月16日盘中最高价报6 3元。12月1

2022-12-16 15:26:02

当前视点!三环集团(300408)12月15日主力资金净卖出1770.93万元

​截至2022年12月15日收盘,三环集团(300408)报收于30 68元,上涨2 85%,换手率0 49%,成交量9 13万手,成交额2 81亿元。

2022-12-16 09:03:32

当前热文:陆家嘴(600663.SH)披露重大资产重组预案 股票复牌

​智通财经APP讯,陆家嘴公告,2022年12月15日,公司董事会审议通过《关于公司发行股份及支付现金购买资产并募集配套资金暨关联交易方案的议案》

2022-12-15 20:07:32

抗疫故事|胡艳华:轻伤不下火线的“疫线领头羊”|精选

​“胡书记,你放心休息去吧,我们一定自觉排好队。”10月3日上午,在平顶山市湛河区马庄街道平高社区核酸检测现场,居民们纷纷在劝社区书记...

2022-12-15 15:03:13