go进阶编程:这段代码会不会打印出"defer"

23 阅读2分钟

Go语言代码解析:是否会打印“defer”?

在Go语言的编程实践中,defer语句是一个不可或缺的特性,它允许开发者延迟某个函数或方法的执行,直到包含该defer语句的函数即将返回时才执行。这种特性在资源清理、互斥锁解锁、文件关闭等场景中扮演着重要角色。接下来,我们一同解析下面这段代码,探究其是否会打印出“defer”。

package main

import "fmt"

func main() {
    var a int
    defer func() {
        if err := recover(); err != nil {
            fmt.Println("recover")
        }
    }()

    defer func() {
        a = 1
        fmt.Println("defer")
    }()
    fmt.Println(a)
    panic("panic")
}

代码深度解析

(点击以下区域查看详细解析,不点击则隐藏)

点击查看详细解析
  1. 变量初始化

    • 声明了一个整型变量a,并将其初始化为零值(即0)。
  2. 第一个defer语句

    • 注册了一个匿名函数,该函数包含一个恢复点(recover point),用于捕获可能发生的panic。如果panic发生并被recover捕获,它将输出“recover”。
  3. 第二个defer语句

    • 注册了另一个匿名函数,该函数会修改变量a的值,并输出“defer”。
  4. 打印变量a的初始值

    • 由于变量a尚未被修改,因此会输出0。
  5. 触发panic

    • panic("panic")这行代码会立即中断当前函数的执行,并开始逆序执行已经注册的defer语句。

defer的执行顺序与输出结果

  • 当panic发生时,Go会逆序执行所有已注册的defer语句。
  • 第一个被执行的defer是修改a的值并输出“defer”的那个。因此,会先输出“defer”。
  • 随后,检查是否有panic被recover捕获的defer被执行,捕获到panic并输出“recover”。

值得注意的是,虽然“defer”的输出操作发生在panic触发之后,但在程序真正崩溃(即完全退出)之前。一旦recover执行完毕,程序实际上已经从panic中恢复,但main函数已经结束,程序会正常退出。

总结

这段代码会打印出“defer”。在panic触发后,Go逆序执行了所有defer语句。由于修改a并打印“defer”的defer语句在捕获panic的defer语句之前注册,因此它会先被执行,从而打印出“defer”。随后,recover捕获到panic并打印“recover”,但程序最终会因main函数结束而退出。

希望这个解析能够帮助你更加深入地理解Go中deferpanic/recover的工作机制。