深入理解与使用go之错误处理--实现

发布于:2024-03-21 ⋅ 阅读:(71) ⋅ 点赞:(0)

深入理解与使用go之错误处理–实现

引子

错误管理是构建健壮和可观察的应用程序的一个基本方面,它应该与代码库的任何其他部分一样重要。在Go中,错误管理不像大多数编程语言那样依赖于传统的try/catch机制。相反,错误作为正常返回值返回。那么问题来了:

  • 程序什么时候发生崩溃(panic)
  • 通常处理错误的方式是怎样的
  • 我们应该忽略错误么
  • 在defer里出错应该怎么处理呢
  • 所有的panic错误都是可以捕获的么

我记得刚写程序的时候,感觉对go的错误很茫然,一股脑的忽略错误,像下面这样

// json 解码
_ = json.Unmarshal(data, &User)
// 打开文件
f, _ := os.Open("hello")

或者,我们避无可避,选择这样判断错误

if strings.Contains(err.Error(), "op error") {
   
		return ""
}
return data
  • 如果json解码的是配置文件,忽略错误会直接导致整个程序启动崩溃
  • 打开文件如果没有权限,下面的所有操作直接panic
  • 如果A开发错误内容是小写 “op error” 而B开发是大写 “OP ERROR”, 能判断么

带着上面的这些问题,我们来讨论讨论今天要说的错误处理

错误处理

错误的分类

我觉得开始处理之前,我们很有必要对错误进行一定的分类

  1. 崩溃型错误
    • 系统调用出现的崩溃 如堆栈溢出、数组越界、空指针引用等等
    • 程序限制型崩溃,如初始化过程中的配置读取、日志路径权限等等,出现错误整个程序就不该继续往下走
  2. 普通型错误
    • 错误我们需要处理,比如数据库连接异常 我们进行重试
  3. 正常型错误
    • 数据库因为查询为空返回的错误
    • 文件读取到末尾的EOF错误
    • 我们不感兴趣且对程序执行不会产生重大影响的错误

有了这三个分类,我们来一个一个看

崩溃型错误
  • 系统调用崩溃性错误

    这种错误一般是程序为了避免进一步的不确定行为和数据损坏,而提前退出

    如 数组越界

    a := []int{
         1, 2, 3}
    fmt.Println(a[3])
    

    运行会直接panic

    panic: runtime error: index out of range [3] with length 3
    
    goroutine 1 [running]:
    main.main()
            /data/www/hello/main.go:12 +0x1b
    exit status 2
    
  • 程序限制型

    net/http包的server.go 有段代码

    func checkWriteHeaderCode(code int) {
         
    	if code < 100 || code > 999 {
         
    		panic(fmt.Sprintf("invalid WriteHeader code %v", code))
    	}
    }
    

    原话是:

    // We used to send "HTTP/1.1 000 0" on the wire in responses but there's
    // no equivalent bogus thing we can realistically send in HTTP/2,
    // so we'll consistently panic instead and help people find their bugs
    // early. (We can't return an error from WriteHeader even if we wanted to.)
    我们过去常常在网络上发送“HTTP/1.1 000 0”作为响应,但现在。
    我们不能在HTTP/2中实际发送等同的虚假信息,
    因此,我们将持续恐慌,帮助人们及早发现他们的缺陷。(即使我们想从WriteHeader返回错误,也不能这样做。)
    

    database/sqlsql.go

    func Register(name string, driver driver.Driver) {
         
    	driversMu.Lock()
    	defer driversMu.Unlock()
    	if driver == nil {
         
    		panic("sql: Register driver is nil")
    	}
    	if _, dup := drivers[name]
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到