Golang 邪修: Try-Catch 的 Go 实现 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
CC11001100

Golang 邪修: Try-Catch 的 Go 实现

  •  1
     
  •   CC11001100
    CC11001100 2023 年 3 月 7 日 3112 次点击
    这是一个创建于 1145 天前的主题,其中的信息可能已经有所发展或是发生改变。

    看 v 友们对 golang 错误处理比较感兴(si)趣(bi)( https://v2ex.com/t/921483 ),看热闹不嫌事大,更新 Golang 邪修系列,之前基于状态机实现的 try-catch-finally 。。。

    项目地址: https://github.com/golang-infrastructure/go-try-catch

    Try-Catch 的 Go 实现

    一、这是什么?为什么会有这个?

    在其他语言中有 try-catch 的实现,但是在 Go 里面并没有提供 try-cach 的实现,更蛋疼的是 Go 里面很多操作又很容易 panic ,对 panic 的捕获很麻烦,粒度不好区分,因此就想着能不能引入一个库解决一部分这种问题。

    当然这种方式并不是一个好的最佳实践,只是我们需要让业务能够正常跑起来更健壮以免隔三差五背锅,仅此而已!

    最后,切记:错误应该被尽早的暴露出来,而不是一味的掩盖!

    二、安装

    go get -u github.com/golang-infrastructure/go-try-catch 

    三、Try-Catch 方法

    提供了两种 helper 方法,一种是比较轻量级的方法,比如当有一段代码需要执行,但是不确定会不会产生错误,就可以这个样子:

    package main import ( "errors" try_catch "github.com/golang-infrastructure/go-try-catch" "github.com/stretchr/testify/assert" "testing" ) func TestTryCatch(t *testing.T) { var errFoo = errors.New("foo") // 正常执行 err := try_catch.TryCatch(func() { t.Log("ok") }) assert.Nil(t, err) // 执行时发生 panic err = try_catch.TryCatch(func() { panic(errFoo) }) assert.NotNil(t, err) assert.ErrorIs(t, err, errFoo) } 

    如果需要返回值的话:

    func TestTryCatchReturn(t *testing.T) { var errFoo = errors.New("foo") // 正常执行 v, err := try_catch.TryCatchReturn(func() int { return 10086 }) assert.Nil(t, err) assert.Equal(t, 10086, v) // 执行时发生 panic v, err = try_catch.TryCatchReturn(func() int { panic(errFoo) }) assert.NotNil(t, err) assert.ErrorIs(t, err, errFoo) } 

    如果需要更多返回值:

    func TryCatchReturn2[R1, R2 any](f func() (R1, R2)) (r1 R1, r2 R2, err error) func TryCatchReturn3[R1, R2, R3 any](f func() (R1, R2, R3)) (r1 R1, r2 R2, r3 R3, err error) 

    四、Try-Catch 方法链

    try-catch 方法链就是定义了一些节点表示异常处理流程中的不同阶段,然后每个节点绑定对应的动作向下一阶段转移,整个状态图大概是这个样子的,其中节点是 Struct ,边是方法:

    graphviz

    Example:

    package example import ( "errors" "fmt" try_catch "github.com/golang-infrastructure/go-try-catch" "testing" ) func Test(t *testing.T) { // 正常执行 try_catch.Try(func() { fmt.Println("ok") }).Do() // try 发生异常,走 catch var errFoo = errors.New("") try_catch.Try(func() { panic(errFoo) }).Catch(errors.New("bar"), func(err error) { fmt.Println("bar") }).Catch(errFoo, func(err error) { fmt.Println("foo") }).Do() // try 发生异常,走默认 catch try_catch.Try(func() { panic(errors.New("test")) }).Catch(errors.New("bar"), func(err error) { fmt.Println("bar") }).Catch(errFoo, func(err error) { fmt.Println("foo") }).DefaultCatch(func(err error) { fmt.Println("other") }).Do() // try 未发生异常走 else try_catch.Try(func() { _ = 100 + 19 }).DefaultCatch(func(err error) { fmt.Println("other") }).Else(func() { fmt.Println("else") }).Do() // try 发生异常,并且走 finally try_catch.Try(func() { panic(errors.New("test")) }).DefaultCatch(func(err error) { fmt.Println("other") }).Else(func() { fmt.Println("else") }).Finally(func() { fmt.Println("finally") }).Do() // try 未发生异常,并且走 finally try_catch.Try(func() { _ = 100 + 19 }).DefaultCatch(func(err error) { fmt.Println("other") }).Finally(func() { fmt.Println("finally") }).Do() // 发生 panic ,尝试捕获错误,但是没有捕获得到,则异常会被向上抛出,即仍然会 panic try_catch.Try(func() { panic(errors.New("test")) }).Catch(errFoo, func(err error) { fmt.Println("catch success") }).Finally(func() { fmt.Println("not catch finally") }).Do() } 
    9 条回复    2023-04-15 00:11:25 +08:00
    shynome
        1
    shynome  
       2023 年 3 月 7 日 via Android
    已经用了蛮久了,很快就要 1.0 了
    https://github.com/lainio/err2
    bv
        2
    bv  
       2023 年 3 月 7 日
    https://github.com/golang-infrastructure/go-try-catch/blob/3e523598eac40c320f42ffc50d2356ce41d1a5b1/try_catch_func.go#L9

    这些 recovery 里面都把 r 断言成了 r.(error),框架不能保证使用者 func 发生 panic 的时候传入的一定是 error 类型。这样会造成 defer recovery 里面继续 panic
    fregie
        3
    fregie  
       2023 年 3 月 7 日 via Android
    golang 工程特性优点 -1
    FrankAdler
        4
    FrankAdler  
       2023 年 3 月 7 日 via iPhone   1
    跟自己写 recover 没区别,不建议使用+1
    FreeWong
        5
    FreeWong  
       2023 年 3 月 7 日 via Android
    一直觉得 判断 error 非常好
    me262
        6
    me262  
       2023 年 3 月 7 日
    不上生产非好汉
    raysonlu
        7
    raysonlu  
       2023 年 3 月 7 日
    @FreeWong 如何把控每个地方可能出现的 error 类型?
    bthulu
        8
    bthulu  
       2023 年 3 月 7 日
    你这样太麻烦了, 不如下面这样的, 只要在需要 try-catch 的代码上下加 try()和 catch()就行了,别的什么都不用干。
    try()
    doSomething()
    catch(err)
    CC11001100
        9
    CC11001100  
    OP
       2023 年 4 月 15 日
    @bv 大佬说的是,刚看了下确实会有这个问题,感谢指正
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1432 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 44ms UTC 16:59 PVG 00:59 LAX 09:59 JFK 12:59
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86