go语言异常处理 error panic recover defer

error panic defer

python中可以用 try except来接收处理异常
go语言没有这些
go的错误分为两种,一种是人工手动抛出的错误error, 一种是程序执行出错的异常panic

defer

func DoDefer(){
    fmt.Println("在defer之前执行")
    defer fmt.Println("第一个defer")
    defer func() {
        fmt.Println("第二个defer")
    }()
    fmt.Println("我在defer中间,我也执行了")
    defer fmt.Println("第三个defer")
    fmt.Println("函数最后的语句执行了")
}

func main() {
    DoDefer()
}

执行结果:

在defer之前执行
我在defer中间,我也执行了
函数最后的语句执行了
第三个defer
第二个defer
第一个defer

结论:
defer执行时间: 函数其他语句执行完之后
defer执行顺序: 堆栈顺序,从下往上
所以说函数中除defer语句之外的代码执行完之后,函数执行完毕,函数指令的堆栈触底上弹,此时开始从下往上执行注册的defer
defer翻译的意思是推迟,可以理解为是一个执行钩子,并且只在函数执行触底后出栈时才会执行(报错,panic也会导致函数提前出栈)

panic

panic是严重异常,如果不进行捕获的话,会导致程序退出
可以通过recover进行捕获,需要配合defer关键字

func panicErr(info string) {
    panic("Panic Error " + info)
}

func MustError() {
    defer func() {
        err := recover()
        fmt.Println("Yes, Cover error", err)
    }()
    fmt.Println("异常之前,即将触发异常")
    panicErr("After")
    fmt.Println("异常之后,异常函数内的代码仍然执行了")
}

func main() {
    MustError()
    fmt.Println("异常发生后,异常函数之外的代码仍然执行了")
}

执行结果:

异常之前,即将触发异常
Yes, Cover error Panic Error After
异常发生后,异常函数之外的代码仍然执行了

可以看到,在执行出错的函数之前通过defer注册出栈的函数,当注册之后的函数抛出panic后,会进行正常捕获,捕获的函数MustError内,代码执行按照通常异常处理的方式中断,并且出栈,该函数出错语句之后的代码不再执行
函数的调用者函数依然可以正常执行

这和try except / try catch不通,try语法处理完try代码块内的代码,不影响函数try外的代码执行
但是defer recover 不行,只要报错,整个函数立即终止

再看另个形式:

func panicErr(info string) {
    panic("Panic Error " + info)
}

func MustError() {
    panicErr("Before")
    defer func() {
        err := recover()
        fmt.Println("Yes, Cover error", err)
    }()
    fmt.Println("异常之前,即将触发异常")
    panicErr("After")
    fmt.Println("异常之后,异常函数内的代码仍然执行了")
}

func main() {
    MustError()
    fmt.Println("异常发生后,异常函数之外的代码仍然执行了")
}

和上面不同的是,在defer注册出栈函数之前,先执行了一次抛出错误的函数,结果就是defer语句无效了
因为代码入栈仍然是从上往下,还没到注册defer,就已经报错了,所以出栈的时候defer的recover还没注册,自然执行不到了

所以,defer语句,最好在函数最开始就定义!!!

error

error在go里面是error接口的实例,不是异常,更像是一个专用于错误信息的类
函数通过return的方式来抛出异常,不会像panic或者Python Exception 那样不断往上抛出直到被捕获,如果不接收,代码编译会出错,如果不想处理,可以用 _ 来接收,接收后不进行处理也不会出错, 但是可能会造成编程人员对程序运行的期望出现偏差。

error更像是一种报警信息,告诉程序员函数调用出现了意料之外的情况,需要注意,或者做相应处理
error不像panic那样强制性的必须处理。

上一篇:golang学习随便记6


下一篇:Go 面试每天一篇(第 19 天)