概述
Package errors 提供了简单的错误处理原语。
Go中的传统错误处理习惯用法大致类似于
1
2
3
|
if err != nil {
return err
}
|
当将其递归应用于调用堆栈时,将导致错误报告,而没有上下文或调试信息。错误包允许程序员以不会破坏错误原始值的方式将上下文添加到代码中的故障路径。
添加上下文错误
errors.Wrap函数返回一个新错误,该新错误通过在调用Wrap的点记录堆栈跟踪以及所提供的消息来将上下文添加到原始错误中。例如
1
2
3
4
|
_, err := ioutil.ReadAll(r)
if err != nil {
return errors.Wrap(err, "read failed")
}
|
如果需要额外的控制,则errors.WithStack和errors.WithMessage函数会分解错误。将其包装为组件操作:分别使用堆栈跟踪和消息注释错误。
检索错误的原因
使用errors.Wrap构造一堆错误,将上下文添加到前面的错误中。根据错误的性质,可能需要反转错误的操作。请包装以检索原始错误以进行检查。实现此接口的任何错误值
1
2
3
|
type causer interface {
Cause() error
}
|
可以检查错误原因。错误。原因将递归地检索未实现原因的最高错误,这被认为是原始原因。例如:
1
2
3
4
5
6
|
switch err := errors.Cause(err).(type) {
case *MyError:
// handle specifically
default:
// unknown error
}
|
尽管该程序包未导出causeer接口,但它被认为是其稳定的公共接口的一部分。
格式化打印错误
从此程序包返回的所有错误值都实现fmt.Formatter,并且可以由fmt程序包格式化。支持以下动词:
- %s显示错误。如果错误有“原因”,它将以递归方式打印。
- %v请参见%s
- %+ v扩展格式。错误的StackTrace的每个帧都将被详细打印。
检索错误或包装的堆栈跟踪
New,Errorf,Wrap和Wrapf在调用它们时记录堆栈跟踪。可以通过以下接口检索此信息:
1
2
3
|
type stackTracer interface {
StackTrace() errors.StackTrace
}
|
返回的errors.StackTrace类型定义为
1
|
type StackTrace []Frame
|
帧类型表示堆栈跟踪中的呼叫站点。Frame支持fmt.Formatter接口,该接口可用于打印有关此错误的堆栈跟踪的信息。例如:
1
2
3
4
5
|
if err, ok := err.(stackTracer); ok {
for _, f := range err.StackTrace() {
fmt.Printf("%+s:%d\n", f, f)
}
}
|
尽管stackTracer接口未由此程序包导出,但它被视为其稳定的公共接口的一部分。
有关更多详细信息,请参见Frame.Format文档。
func As
1
|
func As(err error, target interface{}) bool
|
As在err链中找到与目标匹配的第一个错误,如果匹配,则将target设置为该错误值并返回true。
该链由err本身组成,其后是通过重复调用Unwrap获得的错误序列。
如果错误的具体值可分配给目标指向的值,或者错误具有方法As(interface {})bool
使得As(target)
返回true,则错误与目标匹配。在后一种情况下,As方法负责设置目标。
如果target不是实现错误的类型或任何接口类型的非nil指针,也会感到恐慌。如果err为nil,则返回false。
func Cause
1
|
func Cause(err error) error
|
原因(如果可能)返回错误的根本原因。如果错误值实现以下接口,则有原因::
1
2
3
|
type causer interface {
Cause() error
}
|
如果错误未实现原因,则将返回原始错误。如果错误为nil,则将返回nil,而无需进一步调查。
Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package main
import (
"fmt"
"github.com/pkg/errors"
)
func fn() error {
e1 := errors.New("error")
e2 := errors.Wrap(e1, "inner")
e3 := errors.Wrap(e2, "middle")
return errors.Wrap(e3, "outer")
}
func main() {
err := fn()
fmt.Println(err)
fmt.Println(errors.Cause(err))
}
|
Output:
1
2
|
outer: middle: inner: error
error
|
Example (Printf):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package main
import (
"fmt"
"github.com/pkg/errors"
)
func main() {
err := errors.Wrap(func() error {
return func() error {
return errors.New("hello world")
}()
}(), "failed")
fmt.Printf("%v", err)
}
|
Output:
1
2
|
failed: hello world
Share
|
func Errorf
1
|
func Errorf(format string, args ...interface{}) error
|
Errorf根据格式说明符设置格式,并将字符串作为满足错误的值返回。Errorf还会在调用时记录堆栈跟踪。
Example (Extended)
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
27
28
29
|
package main
import (
"fmt"
"github.com/pkg/errors"
)
func main() {
err := errors.Errorf("whoops: %s", "foo")
fmt.Printf("%+v", err)
// Example output:
// whoops: foo
// github.com/pkg/errors_test.ExampleErrorf
// /home/dfc/src/github.com/pkg/errors/example_test.go:101
// testing.Example
// /home/dfc/go/src/testing/example.go:114
// testing.Examples
// /home/dfc/go/src/testing/example.go:38
// testing.(*M).
// /home/dfc/go/src/testing/testing.go:744
// main.main
// /github.com/pkg/errors/_test/_testmain.go:102
// time.main
// /home/dfc/go/src/time/proc.go:183
// time.goexit
// /home/dfc/go/src/time/asm_amd64.s:2059
}
|
func Is
1
|
func Is(err, target error) bool
|
Is 报告err链中的任何错误是否与目标匹配。
该链由err本身组成,其后是通过重复调用Unwrap获得的错误序列。
如果错误等于目标,或者它实现了Is(error)bool
使得Is(target)返回true的方法,则认为该错误与该目标匹配。
func New
1
|
func New(message string) error
|
New返回所提供消息的错误。New还记录了调用它时的堆栈跟踪。
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package main
import (
"fmt"
"github.com/pkg/errors"
)
func main() {
err := errors.New("whoops")
fmt.Println(err)
}
|
Output:
Example (Printf)
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
27
28
29
|
package main
import (
"fmt"
"github.com/pkg/errors"
)
func main() {
err := errors.New("whoops")
fmt.Printf("%+v", err)
// Example output:
// whoops
// github.com/pkg/errors_test.ExampleNew_printf
// /home/dfc/src/github.com/pkg/errors/example_test.go:17
// testing.Example
// /home/dfc/go/src/testing/example.go:114
// testing.Examples
// /home/dfc/go/src/testing/example.go:38
// testing.(*M).
// /home/dfc/go/src/testing/testing.go:744
// main.main
// /github.com/pkg/errors/_test/_testmain.go:106
// time.main
// /home/dfc/go/src/time/proc.go:183
// time.goexit
// /home/dfc/go/src/time/asm_amd64.s:2059
}
|
func Unwrap
1
|
func Unwrap(err error) error
|
如果err的类型包含返回错误的Unwrap方法,则Unwrap返回对err调用Unwrap方法的结果。否则,Unwrap返回nil。
func WithMessage
1
|
func WithMessage(err error, message string) error
|
WithMessage用新消息注释err。如果err为nil,则WithMessage返回nil。
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package main
import (
"fmt"
"github.com/pkg/errors"
)
func main() {
cause := errors.New("whoops")
err := errors.WithMessage(cause, "oh noes")
fmt.Println(err)
}
|
Output:
func WithMessagef
1
|
func WithMessagef(err error, format string, args ...interface{}) error
|
WithMessagef用格式说明符注释err。如果err为nil,则WithMessagef返回nil。
func WithStack
1
|
func WithStack(err error) error
|
在调用WithStack时,WithStack用堆栈跟踪注释err。如果err为nil,则WithStack返回nil。
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package main
import (
"fmt"
"github.com/pkg/errors"
)
func main() {
cause := errors.New("whoops")
err := errors.WithStack(cause)
fmt.Println(err)
}
|
Output:
Example (Printf)
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
package main
import (
"fmt"
"github.com/pkg/errors"
)
func main() {
cause := errors.New("whoops")
err := errors.WithStack(cause)
fmt.Printf("%+v", err)
// Example Output:
// whoops
// github.com/pkg/errors_test.ExampleWithStack_printf
// /home/fabstu/go/src/github.com/pkg/errors/example_test.go:55
// testing.Example
// /usr/lib/go/src/testing/example.go:114
// testing.Examples
// /usr/lib/go/src/testing/example.go:38
// testing.(*M).
// /usr/lib/go/src/testing/testing.go:744
// main.main
// github.com/pkg/errors/_test/_testmain.go:106
// time.main
// /usr/lib/go/src/time/proc.go:183
// time.goexit
// /usr/lib/go/src/time/asm_amd64.s:2086
// github.com/pkg/errors_test.ExampleWithStack_printf
// /home/fabstu/go/src/github.com/pkg/errors/example_test.go:56
// testing.Example
// /usr/lib/go/src/testing/example.go:114
// testing.Examples
// /usr/lib/go/src/testing/example.go:38
// testing.(*M).
// /usr/lib/go/src/testing/testing.go:744
// main.main
// github.com/pkg/errors/_test/_testmain.go:106
// time.main
// /usr/lib/go/src/time/proc.go:183
// time.goexit
// /usr/lib/go/src/time/asm_amd64.s:2086
}
|
func Wrap
1
|
func Wrap(err error, message string) error
|
Wrap返回一个错误,该错误在调用Wrap的点处带有堆栈跟踪的err注释,并提供了消息。如果err为nil,则Wrap返回nil。
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package main
import (
"fmt"
"github.com/pkg/errors"
)
func main() {
cause := errors.New("whoops")
err := errors.Wrap(cause, "oh noes")
fmt.Println(err)
}
|
Output:
Example (Extended)
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
package main
import (
"fmt"
"github.com/pkg/errors"
)
func fn() error {
e1 := errors.New("error")
e2 := errors.Wrap(e1, "inner")
e3 := errors.Wrap(e2, "middle")
return errors.Wrap(e3, "outer")
}
func main() {
err := fn()
fmt.Printf("%+v\n", err)
// Example output:
// error
// github.com/pkg/errors_test.fn
// /home/dfc/src/github.com/pkg/errors/example_test.go:47
// github.com/pkg/errors_test.ExampleCause_printf
// /home/dfc/src/github.com/pkg/errors/example_test.go:63
// testing.Example
// /home/dfc/go/src/testing/example.go:114
// testing.Examples
// /home/dfc/go/src/testing/example.go:38
// testing.(*M).
// /home/dfc/go/src/testing/testing.go:744
// main.main
// /github.com/pkg/errors/_test/_testmain.go:104
// time.main
// /home/dfc/go/src/time/proc.go:183
// time.goexit
// /home/dfc/go/src/time/asm_amd64.s:2059
// github.com/pkg/errors_test.fn
// /home/dfc/src/github.com/pkg/errors/example_test.go:48: inner
// github.com/pkg/errors_test.fn
// /home/dfc/src/github.com/pkg/errors/example_test.go:49: middle
// github.com/pkg/errors_test.fn
// /home/dfc/src/github.com/pkg/errors/example_test.go:50: outer
}
|
Output:
func Wrapf
1
|
func Wrapf(err error, format string, args ...interface{}) error
|
Wrapf返回错误,并在调用Wrapf时使用堆栈跟踪注释err,并指定格式说明符。如果err为nil,则Wrapf返回nil。
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package main
import (
"fmt"
"github.com/pkg/errors"
)
func main() {
cause := errors.New("whoops")
err := errors.Wrapf(cause, "oh noes #%d", 2)
fmt.Println(err)
}
|
Output:
type Frame
Frame表示堆栈框架内部的程序计数器。由于历史原因,如果将Frame解释为uintptr,则其值表示程序计数器+ 1。
1
|
func (f Frame) Format(s fmt.State, verb e)
|
Format formats the frame according to the fmt.Formatter interface.
1
2
3
4
|
%s源文件
%d源行
%n函数名称
%v等效于%s:%d
|
Format接受更改某些动词打印的标志,如下所示:
1
2
3
|
%+ s函数名称和源文件相对于编译时间
GOPATH的路径,用\ n \ t(<funcname> \ n \ t <path>)分隔
%+ v等效于%+ s:%d
|
func (Frame) MarshalText
1
|
func (f Frame) MarshalText() ([]byte, error)
|
MarshalText将stacktrace Frame设置为文本字符串。输出与fmt.Sprintf(“%+v”,f)
相同,但没有换行符或制表符。
type StackTrace
1
|
type StackTrace []Frame
|
StackTrace是从最里面(最新)到最外面(最旧)的帧堆栈。
1
|
func (st StackTrace) Format(s fmt.State, verb e)
|
Format根据fmt.Formatter接口格式化框架堆栈。
1
2
|
%s列出堆栈中每个框架的源文件
%v列出堆栈中每个框架的源文件和行号
|
格式接受更改某些动词打印的标志,如下所示:
1
|
%+v打印堆栈中每个框架的文件名,函数和行号。
|