浅析go的error
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. go
的1.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
最后期望与你一起遇见更好的自己
期望与你一起遇见更好的自己