Go语言中panic和recover的实现

 更新时间:2025年10月19日 11:43:46   作者:可能只会写BUG  
本文主要介绍了Go语言中panic和recover的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

Go 语言的 panic 和 recover 是两种用于处理异常的机制。

它们允许在程序运行过程中进行错误处理,特别是处理那些不可恢复的错误和恢复程序的执行。

panic 和 recover 并不像其他语言中的 try-catch 机制那样常见,而是提供了控制程序流程的一种方法。

panic 机制

panic 用于表示程序遇到了一个不可恢复的错误,或者程序处于一个不应继续执行的状态。它会触发运行时的异常,并停止当前函数的执行,直到调用 recover 或程序退出。

1.1 panic 的使用

当你遇到一个严重的错误或不合法的操作时,可以调用 panic 来终止当前函数的执行,并开始触发一系列的 defer 函数。

panic 会导致当前函数的执行停止,并且会递归地向上层函数传播,直到程序结束或者有 recover 恢复它。

使用 panic 终止程序

func divide(a, b int) int {
	if b == 0 {
		panic("division by zero") // 如果除数为零,抛出 panic
	}
	return a / b
}

func main() {
	fmt.Println("Starting program")

	// 这里会触发 panic
	result := divide(10, 0)

	fmt.Println("Result:", result) // 这行代码不会执行
}
当 b == 0 时,panic 被触发,程序会停止当前函数的执行,并开始递归传播。

panic 的错误信息是 "division by zero",这将显示在控制台。

调用 panic 后,程序停止执行,任何后续代码都不会被执行,除非在调用链中有 recover。

recover 机制

recover 是 Go 语言中用来从 panic 中恢复的函数。它只能在 defer 中使用。当 recover 被调用时,它会捕获到正在执行的 panic,并停止 panic 继续传播,恢复程序的执行。

2.1 recover 的使用

recover 会返回 panic 时传递的值,并恢复程序的正常执行。

如果 recover 没有在 panic 发生时被调用,panic 会继续向上传播,直到程序退出。

只有在 defer 函数内部,recover 才能捕获到 panic。

使用 recover 恢复程序

func divide(a, b int) int {
	if b == 0 {
		panic("division by zero") // 如果除数为零,抛出 panic
	}
	return a / b
}

func safeDivide(a, b int) (result int, err string) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Sprintf("Recovered from panic: %v", r)
		}
	}()

	result = divide(a, b) // 可能会触发 panic
	return
}

func main() {
	result, err := safeDivide(10, 0)
	if err != "" {
		fmt.Println("Error:", err)
	} else {
		fmt.Println("Result:", result)
	}
}
Error: Recovered from panic: division by zero
safeDivide 函数尝试执行 divide,如果 divide 触发了 panic,recover 会捕获到并停止 panic 继续传播。

defer 中的匿名函数通过 recover() 捕获 panic,并将 panic 的信息作为错误返回。

程序恢复执行并返回错误信息,而不会崩溃。

panic 和 recover 的工作流程

panic 的传播:

当 panic 被触发时,Go 会立即停止当前函数的执行,并开始递归地向上传播 panic。

每次 panic 传播时,都会执行当前函数的所有 defer 语句。

recover 捕获 panic:

如果在某个 defer 语句中调用 recover,它将会捕获当前的 panic 并停止 panic 的传播。

recover 返回 panic 时传递的参数,通常是一个错误信息。

如果没有 recover 捕获,panic 将继续传播,直到程序退出。

panic 和 recover 使用的注意事项

不要滥用 panic 和 recover:Go 语言的设计原则鼓励使用显式的错误处理机制(例如返回错误值),而不是通过 panic 来表示常规错误。panic 应该只用于处理那些程序无法恢复的错误(例如数组越界、无法恢复的逻辑错误等)。

defer 和 recover:recover 必须在 defer 函数中调用才能有效。如果 recover 不在 defer 中,它将无法捕获到 panic。

panic 和 recover 用于同步代码:panic 和 recover 通常用于同步函数的错误处理。它们不能用于并发的错误处理(例如 goroutine 中的错误处理)。对于并发程序,Go 更倾向于通过返回错误值来处理错误。

panic 和 recover 的机制引入了较高的开销,通常应避免在高频调用的代码中使用 panic。它们更适合处理那些异常、不可恢复的错误,而不是正常的程序流程控制。

实际应用中的使用场景

panic 的场景:当程序遇到无法继续执行的严重错误时,调用 panic。例如:空指针解引用、数组越界等。

recover 的场景:当你希望在程序中捕获并恢复某些不可预见的错误时,使用 recover。常见的场景包括:Web 服务器的中间件处理、数据库事务的回滚等。

Web 服务器的 panic 恢复

func handler(w http.ResponseWriter, r *http.Request) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovered from panic:", r)
			http.Error(w, "Internal server error", http.StatusInternalServerError)
		}
	}()

	panic("Something went wrong") // 模拟一个 panic
}


func main() {
	http.HandleFunc("/", handler)
	fmt.Println("Starting server at :8080...")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		fmt.Println("Server failed:", err)
	}
}

服务器启动:当你运行程序时,main 函数启动 HTTP 服务器并监听端口 8080。

触发 panic:当你访问根路径(http://localhost:8080/)时,handler 函数会被触发。在 handler 函数中,程序会故意执行 panic("Something went wrong"),模拟一个错误的发生。

recover 捕获 panic:panic 触发后,程序会立即停止当前函数的执行。此时,defer 语句中的匿名函数被调用,recover 会捕获到 panic,然后通过 http.Error 返回 500 错误响应给客户端。

恢复并继续执行:由于 recover 捕获并处理了 panic,程序不会崩溃,而是继续执行。

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

相关文章

  • Golang重构wget脚本构建通用并发下载工具的实践指南

    Golang重构wget脚本构建通用并发下载工具的实践指南

    在当今的开发和运维工作中,大文件批量下载是一个常见需求,本文分享如何用Golang构建一个通用高效的并发下载工具,有需要的小伙伴可以了解下
    2025-11-11
  • Go语言sync包与锁实现限制线程对变量的访问

    Go语言sync包与锁实现限制线程对变量的访问

    本文主要介绍了Go语言sync包与锁实现限制线程对变量的访问,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • golang实现动态路由的项目实践

    golang实现动态路由的项目实践

    本文主要介绍了golang实现动态路由项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-05-05
  • Win7环境下搭建Go开发环境(基于VSCode编辑器)

    Win7环境下搭建Go开发环境(基于VSCode编辑器)

    这篇文章主要介绍了Win7环境下搭建Go开发环境(基于VSCode编辑器),需要的朋友可以参考下
    2017-02-02
  • golang解析xml的方法

    golang解析xml的方法

    这篇文章主要介绍了golang解析xml的方法,结合实例形式分析了Go语言针对xml文件的读取与解析的相关技巧,需要的朋友可以参考下
    2016-07-07
  • Golang捕获panic堆栈信息的讲解

    Golang捕获panic堆栈信息的讲解

    今天小编就为大家分享一篇关于Golang捕获panic堆栈信息的讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-04-04
  • Go语言算法之寻找数组第二大元素的方法

    Go语言算法之寻找数组第二大元素的方法

    这篇文章主要介绍了Go语言算法之寻找数组第二大元素的方法,以实例形式分析了不排序、只循环一次来实现寻找数组第二大元素的技巧,是比较典型的算法,需要的朋友可以参考下
    2015-02-02
  • 深入了解Go语言编译链接的过程

    深入了解Go语言编译链接的过程

    Go在编译时会将interface和channel关键字转换成runtime中的结构和函数调用,所以小编觉得很有必要就Go的编译过程理一理做个进行总结,下面就来和小编一起了解一下Go语言编译链接的过程吧
    2023-08-08
  • 一文带你搞懂Golang如何正确退出Goroutine

    一文带你搞懂Golang如何正确退出Goroutine

    在Go语言中,Goroutine是一种轻量级线程,它的退出机制对于并发编程至关重要,下午就来介绍几种Goroutine的退出机制,希望对大家有所帮助
    2023-06-06
  • go语言通过反射获取和设置结构体字段值的方法

    go语言通过反射获取和设置结构体字段值的方法

    这篇文章主要介绍了go语言通过反射获取和设置结构体字段值的方法,实例分析了Go语言反射的使用技巧,需要的朋友可以参考下
    2015-03-03

最新评论