错误类型
发布者:admin 发表于:416天前 阅读数:618 评论:0

Go 中有多种声明错误(Error) 的选项:

errors.New 对于简单静态字符串的错误

fmt.Errorf 用于格式化的错误字符串

实现 Error() 方法的自定义类型

"pkg/errors".Wrap 的 Wrapped errors

返回错误时,请考虑以下因素以确定最佳选择:

这是一个不需要额外信息的简单错误吗?如果是这样,errors.New 足够了。

客户需要检测并处理此错误吗?如果是这样,则应使用自定义类型并实现该 Error() 方法。

您是否正在传播下游函数返回的错误?如果是这样,请查看本文后面有关错误包装 section on error wrapping 部分的内容。

否则 fmt.Errorf 就可以了。

如果客户端需要检测错误,并且您已使用创建了一个简单的错误 errors.New,请使用一个错误变量。

Bad Good

// package foo

func Open() error { return errors.New("could not open") }

// package bar

func use() { if err := foo.Open(); err != nil { if err.Error() == "could not open" { // handle } else { panic("unknown error") } } } |

// package foo

var ErrCouldNotOpen = errors.New("could not open")

func Open() error { return ErrCouldNotOpen }

// package bar

if err := foo.Open(); err != nil { if errors.Is(err, foo.ErrCouldNotOpen) { // handle } else { panic("unknown error") } } |

如果您有可能需要客户端检测的错误,并且想向其中添加更多信息(例如,它不是静态字符串),则应使用自定义类型。

Bad Good

func open(file string) error { return fmt.Errorf("file %q not found", file) }

func use() { if err := open("testfile.txt"); err != nil { if strings.Contains(err.Error(), "not found") { // handle } else { panic("unknown error") } } } |

type errNotFound struct { file string }

func (e errNotFound) Error() string { return fmt.Sprintf("file %q not found", e.file) }

func open(file string) error { return errNotFound{file: file} }

func use() { if err := open("testfile.txt"); err != nil { if _, ok := err.(errNotFound); ok { // handle } else { panic("unknown error") } } } |

直接导出自定义错误类型时要小心,因为它们已成为程序包公共 API 的一部分。最好公开匹配器功能以检查错误。

// package foo

type errNotFound struct {
  file string
}

func (e errNotFound) Error() string {
  return fmt.Sprintf("file %q not found", e.file)
}

func IsNotFoundError(err error) bool {
  _, ok := err.(errNotFound)
  return ok
}

func Open(file string) error {
  return errNotFound{file: file}
}

// package bar

if err := foo.Open("foo"); err != nil {
  if foo.IsNotFoundError(err) {
    // handle
  } else {
    panic("unknown error")
  }
}