golang中的defer recover panic

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

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

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本身是一条语句,会按顺序执行准备上下文,只是后面跟的函数会延迟执行

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

查看所有标签

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

编程大师访谈录

编程大师访谈录

Susan Lammers / 李琳骁、吴咏炜、张菁 / 人民邮电出版社 / 2012-1 / 59.00元

《编程大师访谈录》是对19位计算机行业先驱的采访实录,采访对象包括查尔斯•西蒙尼、比尔•盖茨、安迪•赫兹菲尔德、雷•奥奇、杰夫•拉斯金等。访谈涉及他们软件创造过程的灵感、技术、编程习惯、动机、反思,以及对未来软件的畅想等。问答中集结了这些计算机先驱的精辟言论,处处闪烁着智慧的火花。 《编程大师访谈录》适合IT从业人员阅读。一起来看看 《编程大师访谈录》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具