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

开发 后端
简单来讲,就是在业务代码中使用 panic 的方式来替代 “永无止境” 的 if err != nil。我们一起来看看是怎么做,又有什么优缺点,互相学习一轮。

[[358217]]

本文转载自微信公众号「脑子进煎鱼了」,作者陈煎鱼 。转载本文请联系脑子进煎鱼了公众号。  

 大家好,我是煎鱼。

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

简单来讲,就是在业务代码中使用 panic 的方式来替代 “永无止境” 的 if err != nil。

我们一起来看看是怎么做,又有什么优缺点,互相学习一轮。

为什么想替换

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

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 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.

上述还是示例代码,比较直面。若是在工程实践,还得各种 package 跳来跳去加 if err != nil,讲更繁琐,要去关心整体的上下游。

其余更具体的就不赘述了,可以关注我的公众号翻看先前的文章。

怎么替换 err != nil

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

示例代码如下:

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 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.

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

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

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

同时在转换为使用 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) 
    } 
   } 
  }() 
 } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

每次 panic 后根据其抛出的错误进行断言,识别是否定制的 AppErr 错误类型,若是则可以进行一系列的处理动作。

否则可继续向上 panic 抛出给顶级的 Recovery 方法进行处理。

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

优缺点

  • 从优点上来讲:
    • 整体代码结构看起来更加的简洁,仅专注于实现逻辑即可。
    • 不需要关注和编写冗杂的 if err != nil 的错误处理代码。
  • 从缺点上来讲:
    • 认知负担的增加,需要参加项目的每一个新老同学都清楚该模式,要做一个基本规范或培训。
    • 存在一定的性能开销,每次 panic 都存在用户态的上下文切换。
    • 存在一定的风险性,一旦 panic 没有 recover 住,就会导致事故。
    • Go 官方并不推荐,与 panic 本身的定义相违背,也就是 panic 与 error 的概念混淆。

总结

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

 

责任编辑:武晓燕 来源: 脑子进煎鱼了
相关推荐

2025-02-24 09:30:15

2025-03-31 00:29:44

2025-03-31 08:57:25

Go程序性能

2024-06-05 08:47:20

Go语言方式

2014-11-17 10:05:12

Go语言

2021-04-29 09:02:44

语言Go 处理

2023-03-10 08:48:29

2024-02-28 08:54:57

switchGo错误

2022-06-13 07:03:25

Go 语言怎么优化重

2021-09-13 07:53:31

Go错误处理

2022-09-05 08:55:15

Go2提案语法

2022-05-26 08:53:47

Go函数代码

2024-03-14 09:35:54

Go 错误select代码

2021-09-27 15:33:48

Go 开发技术

2023-10-26 15:49:53

Go日志

2021-09-27 23:28:29

Go多协程并发

2021-09-27 10:04:03

Go程序处理

2021-04-14 07:08:14

Nodejs错误处理

2024-03-27 08:18:02

Spring映射HTML

2024-07-26 08:32:44

panic​Go语言
点赞
收藏

51CTO技术栈公众号