深入理解Go语言中defer和panic的执行顺序

 更新时间:2025年05月26日 09:32:25   作者:纸鸢666  
defer 和 panic 的执行顺序是一个重要的概念,本文主要介绍了Go语言中defer和panic的执行顺序,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

简介

在 Go 语言中,defer 和 panic 的执行顺序是一个重要的概念。本文将通过一个示例代码来详细解释为什么 defer 中的代码会先执行,而 panic 的错误信息稍后才输出。

示例代码

package main

import "fmt"

func mayPanic() {
    panic("a problem")
}

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered. Error:\n", r)
        }
    }()

    mayPanic()

    fmt.Println("After mayPanic()")
}

执行顺序解释

1. defer 的执行机制

defer 的作用是延迟执行一个函数调用,直到包含它的函数执行完毕。无论函数是正常结束还是因为错误(如 panic)结束,所有被 defer 延迟的函数都会按照后进先出(LIFO)的顺序执行。

2. panic 的传播机制

当 panic 被触发时,Go 会立即中断当前函数的正常执行流程,并开始向上层调用栈传播错误信号。在这个过程中,Go 会依次执行当前函数中所有被 defer 延迟的函数。这些延迟函数可以通过 recover() 捕获并处理 panic。

3. 代码执行顺序

(1) 执行 main() 函数

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered. Error:\n", r)
        }
    }()

    mayPanic()  // 触发 panic
    fmt.Println("After mayPanic()")  // 这行代码不会执行
}

(2) 调用 mayPanic()

func mayPanic() {
    panic("a problem")
}

panic("a problem") 被触发,程序会立即中断当前函数的执行,并将 panic 信息传播到上层调用栈。

(3) 触发 defer 延迟函数

由于 panic 的触发,Go 会开始执行 main() 函数中被 defer 延迟的函数:

defer func() {
    if r := recover(); r != nil {
        fmt.Println("Recovered. Error:\n", r)
    }
}()

在这个延迟函数中,recover() 被调用,捕获了 panic 的错误信息 "a problem",并打印出来。

(4) panic 被恢复

由于 recover() 成功捕获了 panic,程序的正常执行流程得以恢复。不过,panic 的传播已经中断了 main() 函数的正常执行,因此 fmt.Println("After mayPanic()") 不会执行。

4. 输出结果顺序

按照以上执行顺序,程序的输出如下:

Recovered. Error:
 a problem

为什么 defer 先执行?

这是因为 panic 的传播机制会触发所有 defer 延迟函数的执行。defer 的设计初衷是确保某些重要的清理操作(如释放资源、关闭文件等)能够在函数结束时执行,即使函数是因 panic 而异常结束的。

总结来说:

  • panic 会中断当前函数的执行。

  • Go 会依次执行所有被 defer 延迟的函数。

  • recover() 可以在延迟函数中捕获 panic 并恢复程序的执行。

总结

通过上述代码和解释,我们可以清楚地看到 defer 和 panic 的执行顺序是由 Go 语言的设计规则决定的。defer 确保了清理操作的执行,而 panic 的传播机制允许我们在延迟函数中捕获并处理错误。

到此这篇关于Go语言中defer和panic的执行顺序的文章就介绍到这了,更多相关Go语言 defer和panic执行顺序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go map定义的方式及修改技巧

    Go map定义的方式及修改技巧

    这篇文章主要给大家介绍了关于Go map定义的方式及修改技巧,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • Go gRPC教程实现Simple RPC

    Go gRPC教程实现Simple RPC

    这篇文章主要为大家介绍了Go gRPC教程实现Simple RPC示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Go语言获取文件的名称、前缀、后缀

    Go语言获取文件的名称、前缀、后缀

    这篇文章主要介绍了Go语言获取文件的名称、前缀、后缀,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • 浅析Go汇编语法和MatrixOne使用介绍

    浅析Go汇编语法和MatrixOne使用介绍

    MatrixOne由Go语言所开发是一个新一代超融合异构数据库,致力于打造单一架构处理TP、AP、流计算等多种负载的极简大数据引擎,今天通过本文给大家介绍Go汇编语法和MatrixOne使用,感兴趣的朋友一起看看吧
    2022-04-04
  • Golang实现smtp邮件发送的示例代码

    Golang实现smtp邮件发送的示例代码

    这篇文章主要为大家详细介绍了Golang实现smtp邮件发送的相关知识,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • Golang中for循环的用法示例详解

    Golang中for循环的用法示例详解

    for循环就是让一段代码循环的执行,接下来通过本文给大家讲解Golang中for循环的用法,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-12-12
  • golang连接kafka的示例代码

    golang连接kafka的示例代码

    本文主要介绍了golang连接kafka的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • golang int 转float 强转和高精度转操作

    golang int 转float 强转和高精度转操作

    这篇文章主要介绍了golang int 转float 强转和高精度转操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • go tar包归档文件处理操作全面指南

    go tar包归档文件处理操作全面指南

    这篇文章主要为大家介绍了使用go tar包归档文件处理操作全面指南,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • Golang程序中使用Prometheus的client_golang库

    Golang程序中使用Prometheus的client_golang库

    这篇文章主要介绍了Golang程序中使用Prometheus的client_golang库,Prometheus 是一个开源的监控和警报工具包,用于收集和处理应用程序和系统的指标数据。Prometheus 提供了多种客户端库,可以轻松地集成到各种编程语言中
    2023-04-04

最新评论