异常处理 方法解释:

  • 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

1
2
3
4
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 的一部分。

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
// 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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

# 最后

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

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

更新于 阅读次数

请我喝[咖啡]~( ̄▽ ̄)~*

方小白 微信支付

微信支付

方小白 支付宝

支付宝

方小白 numberpay

numberpay