golang中的defer recover panic

栏目: Go · 发布时间: 5年前

内容简介:先看下面代码执行结果是:结论:

defer

先看下面代码

func main() {
    deferCall()
    fmt.Println("exit main")
}

func deferCall()  {
    defer fmt.Println("defer 1")
    defer func() { fmt.Println("defer 2")}() 

    panic("异常")

    defer func() {
        fmt.Println("defer 3")
        if p := recover(); p != nil {
            fmt.Println("recover", p)
        }
    }()

    time.Sleep(time.Second * 3)
    fmt.Println("after panic")
}

执行结果是:

defer 2
defer 1
panic: 异常
goroutine 1 [running]:
main.deferCall()
Process finished with exit code 2

结论:

  1. defer本身也是一条语句,会按函数过程执行
  2. defer后面跟的函数,会延迟到所在函数退出时执行
    当defer语句被执行时,它后面的函数会被延迟执行,延迟到它所在的函数退出时刻前执行。
  3. panic是函数异常退出的点,panic之后的语句不会执行
    panic同return语句都为函数的退出点,return是正常退出,panic是异常退出,先执行defer后的函数,再return或panic。panic之后声明的defer函数都不会执行
  4. 逆序执行
    多条defer语句时,它后面的函数执行顺序与声明顺序相反
  5. recover要在panic之前声明,否则不能捕获到异常

特别说明:

上面的执行打印结果在终端每次输出都一样,但如果在goland IDE中,输出可能会是先panic: 异常,再defer 2 defer 1。这是因为程序是作为goland的子进程执行的,子进程的stdout,stderr分别通过管道重定向到Goland父进程,因此子进程的fmt.println与panic输出可能会出现乱序的情况。

详细参考:Golang中panic和defer的字符串打印顺序

recover

先看如下代码

func deferCall2()  {

    defer fmt.Println("defer 1")
    defer func() { fmt.Println("defer 2")}()

    defer func() {
        fmt.Println("defer 3")
        if p := recover(); p != nil {
            fmt.Println("recover", p)
        }
    }()

    defer func() { fmt.Println("defer 4")}()

    panic("异常")

    time.Sleep(time.Second * 3)
    fmt.Println("after panic")
}

执行结果:

defer 4
defer 3
recover 异常
defer 2
defer 1
exit main

Process finished with exit code 0

结论:

  1. panic后,逆序执行defer后的函数,遇到recover内置函数后

    recover会使程序从panic中恢复,并返回panic value

defer实现函数trace log

func deferCall3()  {
    // defer表达式会先求值,故下面defer语句会先调用trace函数求得匿名defer函数
    defer trace("deferCall3")()
    time.Sleep(time.Second * 5)
}

func trace(msg string) func() {
    start := time.Now()
    log.Printf("enter %s", msg)
    return func() {
        // start的值,这里牵扯到闭包,上下文的概念
        log.Printf("exit %s (%s)", msg, time.Since(start))
    }
}

执行结果:

2019/06/30 21:20:14 enter deferCall3
2019/06/30 21:20:19 exit deferCall3 (5.004000116s)
exit main

结论:

  1. 验证了结论1,defer本身是一条语句,会按顺序执行准备上下文,只是后面跟的函数会延迟执行

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Trading and Exchanges

Trading and Exchanges

Larry Harris / Oxford University Press, USA / 2002-10-24 / USD 95.00

This book is about trading, the people who trade securities and contracts, the marketplaces where they trade, and the rules that govern it. Readers will learn about investors, brokers, dealers, arbit......一起来看看 《Trading and Exchanges》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换