大家好,我是炸鱼。Go的错误处理一直是最突出的领域。很多同学提出了各种各样的建议,比如:引入try-catch,把iferr!=nil换成panic,引入新的关键字等等,但是这些都被一一否决了。然而,社区仍然没有放弃。周末看到一个新的提案《proposal: runtime: add parameters to recover to only return specific types》很有意思。今天炸鱼就带大家一起来学习。语法解释了Go的panic、recover和defer的基本用法。以下代码:packagemainimport"fmt"funcmayPanic(){panic("aproblem")}funcmain(){deferfunc(){ifr:=recover();r!=nil{fmt.Println("Recovered.Error:\n",r)}}()mayPanic()fmt.Println("AftermayPanic()")}输出结果:恢复。Error:一个问题新的提议是基于原来的Go1兼容性保证一些recover函数进行了一些小的操作。希望可以加参数在运行时恢复,只返回特定类型。函数签名:recover(except...interface{})案例代码:deferfunc(){iferr:=recover(&MyError{},&HelloError{});err!=nil{switche:=err.(type){case*MyError:fmt.Println(e)case*HelloError:fmt.Println(e)}}}上面代码中,recover函数只支持指针MyError和HelloError的类型。然后在处理逻辑中,根据传入的错误类型,对断言进行分类,实际上进行不同的逻辑处理。重点是限制recover的入参类型。讨论可能有小伙伴发现了。比较一下PHP中try-catch的用法。是不是有点类似于之前的提案代码?下面的代码:{echo$e->getMessage();}catch(FooException$ex){echo$e->getMessage();}本质上,这个新提议是在不破坏Go1兼容性的情况下在Go中实现try-catch方式。在交流过程中,社区也发现用户可以在现有机制下独立实现Go的try-catch-like模式。以下代码:funcRecover(expect...interface{})interface{}{iferr:=recover();err!=nil{iflen(expect)==0{returnerr}rv1:=reflect.Indirect(reflect.ValueOf(err))for_,e:=rangeexpect{rv2:=reflect.Indirect(reflect.ValueOf(e))ifrv1.Type()==rv2.Type(){returnerr}}panic(err)}returnnil}这种自制方法的问题是每次Recoverpanic都会将堆栈深度增加2。因此,还是希望Go官方能在运行时支持一下。对Go标准库的使用比较也有一定的作用。涉及的代码基本上是:标准库中至少有以下几个地方可以复用:text/template/exec.gogo/parser/interface.gogo/types/check.gogo/ast/print.goencoding/json/encode.goencoding/gob/error.go总结一下,这个提案本质上是希望通过在recover函数中加入输入控制,配合内部逻辑,实现一个类似于Go版本的try-catch错误处理机制模型,而且其实还有空间以便在Go标准库中重用。但现阶段对提案众说纷纭,有人认为可以由用户自己实现,所以没必要增加复杂度,做这个收益不足的实现。你认为这是否可以填补Go错误处理机制中的一些缺陷?文章持续更新中。可以微信搜索【脑补炸鱼】阅读。本文已收录在GitHubgithub.com/eddycjy/blog中。学习Go语言可以看Go学习地图和路线。欢迎星星提醒。Go书系列Go语言入门系列:Go项目实战Go语言编程之旅初探:以Go为项目深入使用Go语言设计哲学:Go语言进阶之旅:Go语言进阶之旅:深入Go源代码
