本文主要介绍golang如何处理错误。

处理方法

错误码或字符串

一般是对外接口采用的方法,特别是需要序列化(如JSON)的情况。

errors package

使用 errors 包来处理错误:

  • New, Errorf, Wrap, and Wrapf
    生成或封装错误。
  • Cause
    提取封装的错误,方便后续根据具体错误类型进行处理。
  • %+v 或 StackTrace
    打印产生错误时的栈回溯信息。

辅助类型

具体参考《Errors are values1》和《Eliminate error handling by eliminating errors2》。

  • 错误是实现error接口的值
  • 错误是可以编程的值

合适的编程可以消除冗长的if err != nil判断。

 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
26
type errWriter struct {
    w   io.Writer
    err error
}

func (ew *errWriter) write(buf []byte) {
    if ew.err != nil {
        return
    }
    
    _, ew.err = ew.w.Write(buf)
}

func writeData() error {
    // ...
    ew := &errWriter{w: fd}
    
    ew.write(p0[a:b])
    ew.write(p1[c:d])
    ew.write(p2[e:f])

    // check error in the end
    if ew.err != nil {
        return ew.err
    }
}

panic+defer+recover

具体参考《The Way to Go3》的处理方式,也是一种消除冗长if err != nil判断的方法。
可以实现类似于异常处理的效果。

 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
26
27
28
29
30
31
32
33
34
35
36
package main

import (
	"fmt"

	"github.com/pkg/errors"
)

func check(err error) {
	if nil != err {
		panic(err)
	}
}

func outer() (err error) {
	defer func() {
		if rerr, ok := recover().(error); ok {
			err = errors.Wrap(rerr, "outer")
		}
	}()

	err = inner()
	check(err)

	return nil
}

func inner() error {
	return errors.New("inner error")
}

func main() {
	err := outer()
	fmt.Printf("%v\n\n", err)
	fmt.Printf("%+v\n", errors.Cause(err))
}

Go 2 check+handle

Go 2预计支持新的错误处理4方式,感兴趣的可以先了解一下。

参考文档


  1. Errors are values ↩︎

  2. Eliminate error handling by eliminating errors ↩︎

  3. 一种用闭包处理错误的模式 ↩︎

  4. Go 2 Error Handling ↩︎