关于golang中的错误处理机制的详细介绍


本文摘自php中文网,作者V,侵删。

基础

错误处理应该是工程的一部分,Golang中的error是一个interface类型,如下:

1

2

3

type error interface {

    Error() string

}

凡是实现Error()方法的结构,都可以作为错误处理。因此如果函数可能出现错误,那么可以在返回值的最后,返回一个错误,比如:

1

2

3

4

func foo() error {

    // ... do something

    return errors.New("foo error")

}

直接返回错误

直接返回错误,类似于直接返回字符串类型的错误,或者错误码之类的。字符串类型的错误,在基础部分提到了。错误码相当于Linux、C编程中的错误码,一般我们需要自己定义。举个例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

package mypkg

 

type ErrCode int

 

const (

    ERR1 = 1

    ERR2 = 2

    ERR3 = 3

)

 

func sub(a, b int) (int, ErrCode) {

    if b < 0 {

        return 0, ERR1

    } else if a < b {

        return 0, Err2

    } else if a < 0 {

        return 0, Err3

    }

    return a - b

}

这种类型的错误,编写简单,但是有两个缺陷:

1、外层如果想要使用错误码,则需要引入这个包,容易出现循环引用的情况。

2、如果包内部修改返回的错误码类型,则外部使用到错误码的地方,都要进行相应的修改,破坏了封闭性。

对于第一个缺陷,可以使用一个第三方的包,专门存放错误码,这个方式值得商榷。永远不要通过判断Error()方法返回的字符串的值,来进行对应的错误处理!!!

返回自定义类型的错误

该方式可以返回自定义的类型,并通过断言自定义类型,来进行有关的错误处理;自定义类型可以携带更多的信息,代码实例:

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

package main

 

import (

    "errors"

    "fmt"

    "runtime/debug"

)

 

type MyError struct {

    Inner      error                  // 内粗错误

    Message    string                 // 自定义错误信息

    StackTrace string                 // 堆栈信息

    Misc       map[string]interface{} //其它的一些数据

}

 

func (myError MyError) Error() string {

    return myError.Message

}

 

func wrapError(err error, msg string, msgArgs ...interface{}) MyError {

    return MyError{

        Inner:      err,

        Message:    fmt.Sprintf(msg, msgArgs),

        StackTrace: string(debug.Stack()),

        Misc:       make(map[string]interface{}),

    }

}

 

func Handle(key int) error {

    if key < 0 {

        return wrapError(errors.New("key < 0"), "This is an error test")

    }

    return nil

}

 

func main() {

    if err := Handle(-1); err != nil {

        if e, ok := err.(MyError); ok {

            fmt.Printf("Inner: %v, Message: %v, StackTrace: %v\n",

                e.Inner, e.Message, e.StackTrace)  // 这里输出对应的数据

        }

    }

}

这种方式处理问题更加方便,但是仍然可能会有包循环引用的问题。

隐藏内部细节的错误处理

上述两种方式,可以适应一些场景,不过都无法解决可能存在循环依赖的问题。为此,我们使用github.com/pkg/errors的包来解决问题,给出一个代码实例。

1

func New(message string) error

如果有一个现成的error,我们需要对他进行再次包装处理,这时候有三个函数可以选择。

1

2

3

4

5

6

//只附加新的信息

func WithMessage(err error, message string) error

//只附加调用堆栈信息

func WithStack(err error) error

//同时附加堆栈和信息

func Wrap(err error, message string) error

其实上面的包装,很类似于Java的异常包装,被包装的error,其实就是Cause,在前面的章节提到错误的根本原因,就是这个Cause。所以这个错误处理库为我们提供了Cause函数让我们可以获得最根本的错误原因。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

func Cause(err error) error {

    type causer interface {

        Cause() error

    }

 

    for err != nil {

        cause, ok := err.(causer)

        if !ok {

            break

        }

        err = cause.Cause()

    }

    return err

}

使用for循环一直找到最根本(最底层)的那个error。

相关文章教程推荐:golang教程

以上就是关于golang中的错误处理机制的详细介绍的详细内容,更多文章请关注木庄网络博客!!

相关阅读 >>

golang反向代理无法访问

一道有趣的golang排错题

golang如何获取目录下文件是否存在

怎么安装godoc

手撸golang 学etcd 手写raft协议之12 单元测试

解析golang iris怎么使用

golang怎么给slice赋长度

聊聊golang的ddd项目结构

聊聊dubbo-go-proxy的discoveryservice

golang是什么语言

更多相关阅读请进入《golang》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...