您现在的位置是:亿华云 > 数据库

试试动 Go recover 刀子,看看能不能优化错误处理?

亿华云2025-10-03 20:33:02【数据库】6人已围观

简介大家好,我是煎鱼。Go 的错误处理一直是表现最突出的一块地方,许许多多的同学都提出了各种提案,例如:引入 try-catch、用 panic 代替 if err != nil、引入新的关键字等。但这些

大家好,试试我是动G刀煎鱼。

Go 的优化错误处理一直是表现最突出的一块地方,许许多多的错误处理同学都提出了各种提案,例如:引入 try-catch、试试用 panic 代替 if err != nil、动G刀引入新的优化关键字等。但这些都被一一驳回了。错误处理

不过社区依然还没放弃,试试周末看到有一个新的动G刀提案《proposal: runtime: add parameters to recover to only return specific types[1]》挺有意思。

今天就由煎鱼带大家一起学习。优化

语法说明

Go 的错误处理 panic、recover、试试defer 的动G刀基本使用方式。如下代码:

package main

import "fmt"

func mayPanic() {

panic("a problem")

}

func main() {

defer func() {

if r := recover(); r != nil {

fmt.Println("Recovered. Error:\n",优化 r)

}

}()

mayPanic()

fmt.Println("After mayPanic()")

}

输出结果:

Recovered. Error:

a problem新提案

由于有 Go1 兼容性保障,新提案是在原有的 recover 函数上动小手术。希望可以现在运行时的源码库 recover 中加入参数,仅支持返回特定的类型。

函数签名:

recover(except ...interface{ })

案例代码:

defer func(){

if err := recover(&MyError{ }, &HelloError{ }); err != nil {

switch e := err.(type) {

case *MyError:

fmt.Println(e)

case *HelloError:

fmt.Println(e)

}

}

}

上面代码中,recover 函数只支持传入 MyError 和 HelloError 的指针类型。再在处理逻辑中根据所传入的错误类型,进行断言分类,实际上去做不同的逻辑处理。

重点就是限定 recover 入参类型。

讨论

有些小伙伴可能发现了,对比看看 PHP 的 try-catch 的用法,与前面的提案代码是不是有好几分神似呢?

如下代码:

try {

...

}

catch (Exception $e) {

echo $e->getMessage();

}

catch (InvalidArgumentException $e) {

echo $e->getMessage();

}

catch (BarException $ex)

{

echo $e->getMessage();

}

catch (FooException $ex)

{

echo $e->getMessage();

}

本质上这个新的提案是想在不破坏 Go1 兼容性的情况下,在 Go 中实现 try-catch 的方式。

社区在交流时,云服务器提供商也发现了用户在现有机制下可以自主实现 Go 的类 try-catch 的模式。

如下代码:

func Recover(expect ...interface{ }) interface{ } {

if err := recover(); err != nil {

if len(expect) == 0 {

return err

}

rv1 := reflect.Indirect(reflect.ValueOf(err))

for _, e := range expect {

rv2 := reflect.Indirect(reflect.ValueOf(e))

if rv1.Type() == rv2.Type() {

return err

}

}

panic(err)

}

return nil

}

这个自制方法的问题是每次 Recover panic 都会将堆栈深度增加 2。因此还是寄希望于 Go 官方能够在运行时支持。

在 Go 标准库的用途对比上,也有产生一定的作用,其涉及到的代码基本为:

标准库中至少有以下地方可以复用:

text/template/exec.go[2]go/parser/interface.go[3]go/types/check.go[4]go/ast/print.go[5]encoding/json/encode.go[6]encoding/gob/error.go[7]总结

这个提案本质上是希望通过在 recover 函数中增加入参控制,再配合内部逻辑实现类似 Go 版本的 try-catch 的错误处理机制模型,且实际在 Go 标准库中有复用的空间。

但现阶段该提案也是赞同和反对参半,也有人认为可以用户自己实现,那就没必要加大复杂度,去做这个收益不够大的实现。

你觉得这能补全 Go 错误处理的站群服务器一些机制缺陷吗?

参考资料

[1]proposal: runtime: add parameters to recover to only return specific types: https://github.com/golang/go/issues/50424

[2]text/template/exec.go: https://cs.opensource.google/go/go/+/refs/tags/go1.17.5:src/text/template/exec.go;l=156

[3]go/parser/interface.go: https://cs.opensource.google/go/go/+/refs/tags/go1.17.5:src/go/parser/interface.go;l=97

[4]go/types/check.go: https://cs.opensource.google/go/go/+/refs/tags/go1.17.5:src/go/types/check.go;l=235

[5]go/ast/print.go: https://cs.opensource.google/go/go/+/refs/tags/go1.17.5:src/go/ast/print.go;l=53

[6]encoding/json/encode.go: https://cs.opensource.google/go/go/+/refs/tags/go1.17.5:src/encoding/json/encode.go;l=317

[7]encoding/gob/error.go: https://cs.opensource.google/go/go/+/refs/tags/go1.17.5:src/encoding/gob/error.go;l=32

很赞哦!(913)