Go 错误处理:用 panic 取代 err != nil 的模式

如有任何问题或建议,欢迎及时交流和碰撞。个人公众号是 【脑子进煎鱼了】,GitHub 地址: https://github.com/eddycjy

前段时间我分享了文章 《先睹为快,Go2 Error 的挣扎之路》后,和一位朋友进行了一次深度交流,他给我分享了他们项目组对于 Go 错误处理的方式调整。git

简单来说,就是在业务代码中使用 panic 的方式来替代 “永无止境” 的 if err != nil。这就是今天本文的重点内容,咱们一块儿来看看是怎么作,又有什么优缺点。github

为何想替换

在 Go 语言中 if err != nil 写的太多,还要管方法声明各类,嫌麻烦又不方便:sql

err := foo()
if err != nil {
     //do something..
     return err
}

err := foo()
if err != nil {
     //do something..
     return err
}

err := foo()
if err != nil {
     //do something..
     return err
}

err := foo()
if err != nil {
     //do something..
     return err
}

上述仍是示例代码,比较直面。如果在工程实践,还得各类 package 跳来跳去加 if err != nil,总的来说比较繁琐,要去关心总体的上下游。更具体的就不赘述了,能够翻看我先前的文章。架构

怎么替换 err != nil

不想写 if err != nil 的代码,方式之一就是用 panic 来替代他。示例代码以下:app

func GetFish(db *sql.DB, name string) []string {
    rows, err := db.Query("select name from users where `name` = ?", name)
    if err != nil {
        panic(err)
    }
    defer rows.Close()

    var names []string
    for rows.Next() {
        var name string
        err := rows.Scan(&name)
        if err != nil {
            panic(err)
        }

        names = append(names, name)
    }

    err = rows.Err()
    if err != nil {
        panic(err)
    }

    return names
}

在上述业务代码中,咱们经过 panic 的方式取代了 return err 的函数返回,天然其所关联的下游业务代码也就不须要编写 if err != nil 的代码:函数

func main() {
    fish1 := GetFish(db, "煎鱼")
    fish2 := GetFish(db, "咸鱼")
    fish3 := GetFish(db, "摸鱼")
    ...
}

同时在转换为使用 panic 模式的错误机制后,咱们必需要在外层增长 recover 方法:微服务

func AppRecovery() gin.HandlerFunc {
    return func(c *gin.Context) {
        defer func() {
            if err := recover(); err != nil {
                if _, ok := err.(AppErr); ok {
                    // do something...
                } else {
                    panic(err)
                }
            }
        }()
    }
}

每次 panic 后根据其抛出的错误进行断言,识别是否认制的 AppErr 错误类型,如果则能够进行一系列的处理动做。不然可继续向上 panic 抛出给顶级的 Recovery 方法进行处理。性能

这就是一个相对完整的 panic 错误链路处理了。spa

优缺点

  • 从优势上来说:设计

    • 总体代码结构看起来更加的简洁,仅专一于实现逻辑便可。
    • 不须要关注和编写冗杂的 if err != nil 的错误处理代码。
  • 从缺点上来说:

    • 认知负担的增长,须要参加项目的每个新老同窗都清楚该模式,要作一个基本规范或培训。
    • 存在必定的性能开销,每次 panic 都存在用户态的上下文切换。
    • 存在必定的风险性,一旦 panic 没有 recover 住,就会致使事故。
    • Go 官方并不推荐,与 panic 自己的定义相违背,也就是 panicerror 的概念混淆。

总结

在今天这篇文章给你们分享了如何使用 panic 的方式来处理 Go 的错误,其必然有利必有有弊,须要作一个权衡了。

大家团队有没有为了 Go 错误处理作过什么新的调整呢?欢迎在留言区交流和分享。

个人公众号

分享 Go 语言、微服务架构和奇怪的系统设计,欢迎你们关注个人公众号和我进行交流和沟通。

最好的关系是互相成就,各位的点赞就是煎鱼创做的最大动力,感谢支持。

相关文章
相关标签/搜索