Sentinel errors

哨兵模式,例如

if io == io.EOF

优缺点:需要导包,可能循环引用

Error Types

​ 包含error以及其它信息的结构体

优缺点:需要导包,循环引用。但可得到更多的信息。比哨兵模式更好一点。

Opaque errors

黑盒策略,不关心具体错误类型,有错误则返回否则继续或根据是否具有某种行为(实现某种接口)判断是否重试。demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func fn() error {
x, err := bar.Foo()
if err != nil {
return err
}
// use x
return nil
}
//
type temporary interface { Temporary() bool}
func IsTemporary(err error) bool {
te, ok := err.(temporary)
return ok && te.Temporary()
}

pkg/errors

携带一个message并可返回原始error以进行Sentinel errors比较的库:github.com/pkg/errors
可避免在多个层多次处理eror

go1.13标准库的升级

https://www.flysnow.org/2019/09/06/go1.13-error-wrapping.html

  1. errorf %w –>不丢失原error的wrap error。
  2. Unwrap 解一层wrap error
  3. Is wrap chain中是否包含
  4. As error转换(断言)

rob pike:Errors are values

法1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var err error
write := func(buf []byte) {
if err != nil {
return
}
_, err = w.Write(buf)
}
write(p0[a:b])
write(p1[c:d])
write(p2[e:f])
// and so on
if err != nil {
return err
}

法2:

1
2
3
4
5
6
7
8
9
10
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)
}

更加cleaner的法1,且可以反复使用,记录累计字节数等
但无法知道在出错前出现了执行了多少。通常情况下是够用的(多数情况下只需要在最后检查是否全部ok)。

关于Go中错误和异常的思考

不会终止程序逻辑运行的归类为错误,会终止程序逻辑运行的归类为异常。

个人思考

web后端dao,controller层次中的错误处理:
场景:dao层返回部分需要特别捕捉的错误
fmt.Errorf(“dao read something err: %w\n”,err)

中间层检测调用层返回是否error,如果error则直接返回。在本层出现error则返回fmt.Errorf(“相关说明 + 相关参数%v+ %w”,p,err)。只在controller层打印日志。如有其它判断可在相关层借助Is/As/Wrap等函数处理判断。

参考

https://qcrao.com/2019/09/18/golang-error-break-through/#Unwrap
https://go.dev/blog/errors-are-values
https://www.zhihu.com/question/27158146