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

Gotry的新提议靠谱吗?想简化错误处理

时间:2023-03-25 21:57:44 Python

大家好,我是建宇。近日,新的尝试提案《proposal: Go 2: error handling: try statement with handler》在社区内引发热议。今天小编就和大家一起打开剑鱼来看看吧。这可以撤销Go的错误处理机制并重新组织它。背景PingCAP的提案作者@GregWeber将基于两个因素来执行此操作,一个在《Go Developer Survey 2022 Q2 Results》中明确提到。随着Go1.18泛型的发布,原本最矛盾的泛型得到了初步的解决。在社区研究中,开发人员在使用Go时面临的最大挑战已经转移到错误处理上,需要努力“修复”它。还有一个因素就是众所周知,Go的错误处理代码比较繁琐。工程师经常开玩笑说Go项目的30%都是iferr=nil。以下代码:_,err:=f()iferr!=nil{...}_,err=r()iferr!=nil{...}_,err=w()iferr!=nil{...}希望让它更优雅。也有很多小伙伴对这个设计表示赞同,确实是一个简单直观的过程,在社区形成了一定的角力。try-handlerproposal该提案中提到的解决方案是增加一条新的语句try来实现简洁的错误处理,让iferr!=nil的处理更加顺畅。下面的代码:tryerr,handler编译器翻译后生成的代码:iferr!=nil{returnhandler(err)}函数中可以这样:func(args...)(rtype1,rtypes...,rtypeN,error){tryerr,handler...}翻译后生成的代码:func(args...)(rtype1,rtypes...,rtypeN,error){iferr!=nil{returnZero(rtype1),Zeros(rtypes...)...,Zero(rtypeN),handler(err)}...}也可以只处理iferr!=nil。如下代码:tryerr翻译后生成的代码:iferr!=nil{returnerr}不会调用不存在的handler进行处理,直接返回。三行(iferr!=nil逻辑)直接变成3个字(try)。如果不想写函数,也可以直接:x,err:=f()tryerr,fmt.Errorf("ffail:%w",err)defer+try的场景可以是如下:funcCopyFile(src,dststring)error{defertryfunc(errerror)error{returnfmt.Errorf("copy%s%s:%w",src,dst,err)}...}输入参数比较灵活,作者希望是泛型,可以适应各种场景的需求。示例与实践对于这个提案,原作者给出了各种使用场景的示例。如下代码:import("fmt")//这个助手应该在fmt包中定义funcHandlew(formatstring,args...any)func(error)error{returnfunc(errerror)error{args=append(args,err)returnfmt.Errorf(format+":%w",args...)}}//这个helper应该定义在fmtpackagefuncHandlef(formatstring,args...any)func(error)error{returnfunc(errerror)error{args=append(args,err)returnfmt.Errorf(format+":%v",args...)}}funcvalAndError()(int,error){返回1,fmt.Errorf("makeerror")}funcnewGo()(int,error){x,err:=valAndError()tryerr//已经提供了常用的格式化函数i:=2x,err=valAndError()tryerr,Handlew("customError%d",i)//使用自定义错误类型//为了方便错误类型可以暴露一个方法来设置错误x,err=valAndError()tryerr,TheErrorAsHandler(i)}typeTheError结构{numinterrerror}func(tTheError)Error()String{returnfmt.Sprintf("theError%d%v",t.num,t.err)}funcTheErrorAsHandler(numint)func(err)TheError{returnfunc(errerror)TheError{returntheError{num:i,err:err}}}同样在日常的Go工程中,提案作者认为CopyFile函数是一个很好的例子新的提案声明为此,基于try-handler修改并解释了一个好的实践。以下代码://这个助手可以与deferfunchandle(err*error,handlerfunc(errerror)error){iferr==nil{returnnil}*err=handler(err)}funcCopyFile(src,dststring)(errerror){deferhandle(&err,func(errerror)error{returnfmt.Errorf("copy%s%s:%w",src,dst,err)})r,err:=操作系统.Open(src)tryerrdeferr.Close()w,err:=os.Create(dst)tryerr,func(errerror)error{os.Remove(dst)//仅当创建失败时returnfmt.Errorf("dir%s:%w",dst,err)}deferw.Close()err=io.Copy(w,r)tryerrerr=w.Close()tryerrreturnnil}引入try-hanlder后,可以这样做:插入错误的return语句,进行机制预置。在返回错误之前将错误处理函数组合在一起,以方便后续处理。综上所述,在这个新提案中,一旦实施,可以减少如下代码的编写:处理机制“运行”,这是提案的强项。但从Go开发者的角度来看,会引入一些新的副作用,例如:初学者的学习成本、Go工具链的改造、程序理解复杂度的增加。另外,新的语句似乎更难与Go1.13引入的error.Is和As有更好的相关性。如果作为第三方用户库引入还好,但如果作为标准包含在Go源码中,就显得有点格格不入了(提案作者希望进入)。看了这么多提案,Go的错误处理机制的“升级”似乎已经陷入了手心手背都是肉的阶段……文章持续更新中,大家可以搜索【脑补炸鱼】微信阅读,本文已收录GitHubgithub.com/eddycjy/blog。如果你想学习Go语言,可以阅读Go学习地图和路线。欢迎星星提醒。推荐阅读Goonlyiferr!=nil?不对,把这些优雅的搬运姿势分享给你!Go错误处理的新思路?用左边的函数和表达式先睹为快,Go2Error的奋斗之路Go书系列Go语言入门系列:实践中的Go项目初探Go语言编程之旅:深入使用Go做项目Go语言设计理念:Go语言进阶之旅:深入了解源码