浅析go的error

2022年2月24日 447点热度 0人点赞 0条评论

go 中 errors 包的方法解释:


  • New: 创建一个Error
  • Is:判断是不是特定的一个Error
  • As:类型转换为特定的Error
  • UnWrap: 解除包装,返回被包装的error.

error.New(string) 方法返回的是 error struct 的指针。

errors is values. error 其实就是一个interface (struct)

error的类型

Sentinel Error

Sentinel Error 预定义的特定错误.我们称为 Sentinel Error. 这个名字来源于计算机编程中使用一个特定值来表示不可能进一步处理的错误。类似于:io.EOF 或者,更底层的:syscall.ENOENT.

尽可能避免的使用Sentinel Error

func demo1() {
 err := errors.New("this is a error")
 println(err.Error())
}

Error Type (错误类型)

Error Type 是实现了 error 接口的自定义类型。例如下面的MyError. 用户可以使用断言来转换这个错误,获取更多的异常信息。如 下代码. 相比于 Sentinel Error, Error Type的一大改进就是 能够为包装底层 error 提供上下文。例如os.PathError. 但是:调用使用类型断言和类型 switch .就要让自定义的 error 变为 public 。这种模型会导致错误类型和调用者强耦合,从而导致Api变得脆弱。

建议:避免使用 error Type 或者 至少避免将他们作为公共API的一部分。

// MyError /** demo2.
type MyError struct {
 msg        string
 fileName   string
 lineNumber int
}

// 实现了 error接口。
func (m *MyError) Error() string {
 return fmt.Sprintf("%s:%d: %s", m.fileName, m.lineNumber, m.msg)
}

func testError() error {
 return &MyError{msg: "this is a error", fileName: "demo8_error_resolve", lineNumber: 50}
}

func demo2() {
 err := testError()
 switch err := err.(type) {
 case nil:
 case *MyError:
  fmt.Println("error: ", err.lineNumber)
 default:

 }
}

Opaque Error

将这种风格称为 不透明错误. 虽然你知道发生了错误,但是您没能力看到错误的内部,作为调用者,关于操作的结果,您所知道的就是他成功或者失败了
==> 只返回错误,但不返回错误内容。==> 同时返回错误的类型,而不是错误的类型。如下示例:

func Write(w io.Writer, buf []byte) error {
 _, err := w.Write(buf)
 return fmt.Errorf("这里发生了错误,%w\n", err)
}

// OpaqueError /***** demo3
type OpaqueError interface {
 error
 IsTemporary() bool // 是否是临时错误。
 IsTimeout() bool   // 是否是超时
}

type temporary interface {
 Temporary() bool
}

// 判断是否为Temporary Error.
func isTemporary(err error) bool {
 te, ok := err.(temporary)
 return ok && te.Temporary()
}

Handing Error 处理异常

  • 一种处理error的方式,编写代码技巧,让代码更易读。
  • wrap Errors. 使用第三方库。github.com/pkg/errors. go1.13版本之后,可以使用: fmt.Errorf("%w",err). 和 errors.Is(),errors.As(). 规范:
    • 如果是一个跨项目,多重复用的项目里,应该直接返回error, 而不是返回包装后的error.
    • 如果函数/方法不打算处理错误,那么用足够的上下文 wrap error并将其返回到调用堆栈中。
    • 一旦确定函数/方法要处理错误,错误就不再是错误, 如果函数/方法仍然需要发出返回,则它不能返回错误值,它应该只返回零(比如降级处理中, 你返回了 降级数据,然后需要返回nil.)

go 2.x 的发展参考

建议多看看, 可以把握一下 go 未来的发展方向

https://go.googlesource.com/proposal/+/master/design/29934-error-values.md

https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling.md

https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md

最后

期望与你一起遇见更好的自己

图片

期望与你一起遇见更好的自己

28500浅析go的error

这个人很懒,什么都没留下

文章评论