Go Lang 实战

Go函数-错误处理(四)

2019-08-01  本文已影响0人  草莓君_

error

官方推荐的标准做法是返回error状态。

func Scanln(a ...interface{}) (n int, err error)

标准库将error定义为接口类型,以便实现自定义错误类型。

type error interface {
    Error() string
}

按惯例,error总是最后一个返回参数。标准库提供了相关创建函数,可方便地创建包含简单错误文本的error对象。

var errDivByZero = errors.New("division by zero")
func div(x ,y int) (int, error){
    if y == 0 {
        return 0, errDivByZero
    }
    return x /y, nil
}

func main() {

    z, err := div(5,0)
    if err == errDivByZero {
        log.Fatal(err)      //打印输出内容,退出应用程序,defer函数不会执行
    }
    println(z)
}

输出:

2019/08/01 16:27:50 division by zero

某些业务场景,我们想自定义错误类型,怎么做呢?

type DivError struct {          //自定义错误类型
    x ,y int
}

func (DivError) Error() string {    //实现error接口方法
    return "division by zero"
}

func div(x ,y int) (int, error) {
    if y == 0 {
        return 0, DivError{x, y}    //返回自定义错误类型
    }
    return x/y, nil
}

func main() {
    z, err := div(5,0)
    if err != nil {
        switch e := err.(type) {    //根据类型匹配
        case DivError:
            fmt.Println(e, e.x, e.y)
        default:
            fmt.Println(e)
        }
        log.Fatal(err)
    }
    println(z)
}

输出:

division by zero 5 0
2019/08/01 16:40:06 division by zero

panic,recover

与error相比,panic/recover在使用方法上更接近try/catch结构化异常。

func panic(v interfaceP{})
func recover() interface{}

它们是内置函数而非语句。panic会立即中断当前函数流程,执行延迟调用。而在延迟调用中,recover可捕获并返回panic提交的错误对象。

func main() {
    defer func() {
        if err := recover(); err != nil {   //错误捕获
            log.Fatal(err)
        }
    }()
    
    panic("i am dead")      //引发错误
    println("exit.")        //永不会执行
}

输出:

2019/08/01 16:59:17 i am dead

无论是否执行recover,所有延迟调用都会被执行。但中断性错误会沿调用堆栈向外传递,要么被外层捕获,要么导致进程崩溃。
连续调用panic,仅最后一个会被recover捕获

func main() {
    defer func() {
        for {
            if err := recover(); err != nil {
                log.Println(err)
            }else {
                log.Fatal("fatal")
            }
        }
    }()

    defer func() {                  //类似重新抛出异常
        panic("you are dead")   //可先recover捕获,包装后重新抛出
    }()

    panic("i am dead")
}

输出:

2019/08/01 17:52:11 you are dead
2019/08/01 17:52:11 fatal

建议:除非是不可恢复性、导致系统无法正常工作的错误,否则不建议使用panic

上一篇 下一篇

猜你喜欢

热点阅读