Golang panic 函数
最后修改时间 2025 年 5 月 8 日
本教程将讲解如何在 Go 中使用内置的 panic 函数。我们将通过实际的错误处理和恢复示例来介绍 panic 的基本用法。
panic 函数用于停止 Go 中的正常执行。当调用 panic 时,程序将开始展开堆栈,并执行延迟的函数。
在 Go 中,panic 通常用于不可恢复的错误。它应该仅用于程序无法继续执行的异常情况。
基本 panic 示例
panic 最简单的用法是立即停止程序执行。此示例演示了 panic 的基本行为。
注意: 在生产代码中应谨慎使用 panic。
package main
import "fmt"
func main() {
fmt.Println("Starting program")
panic("Something went terribly wrong!")
fmt.Println("This line will never execute")
}
程序打印第一条消息然后 panic。由于执行在 panic 调用处停止,第二条消息永远不会被打印。
带 recover 的 panic
我们可以使用延迟调用中的 recover 函数来从 panic 中恢复。此示例展示了 panic 恢复的实际应用。
package main
import "fmt"
func mayPanic() {
panic("a problem occurred")
}
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
mayPanic()
fmt.Println("After mayPanic()")
}
延迟函数调用 recover 来捕获 panic。程序在从 panic 恢复后继续执行。
goroutine 中的 panic
goroutine 中的 panic 与主程序中的 panic 行为不同。此示例展示了并发代码中的 panic 处理。
package main
import (
"fmt"
"time"
)
func worker() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Worker recovered:", r)
}
}()
panic("Worker failed")
}
func main() {
go worker()
time.Sleep(1 * time.Second)
fmt.Println("Main function continues")
}
worker goroutine panic 了,但它自己进行了恢复。主 goroutine 继续执行,不受 worker panic 的影响。
带自定义类型的 panic
panic 可以接受任何值,包括自定义类型。此示例演示了如何将结构化数据与 panic 一起使用。
package main
import "fmt"
type ErrorDetails struct {
Code int
Message string
}
func processInput(input int) {
if input < 0 {
panic(ErrorDetails{
Code: 400,
Message: "Negative input not allowed",
})
}
fmt.Println("Processing input:", input)
}
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered:", r)
}
}()
processInput(-5)
fmt.Println("Program continues after recovery")
}
当检测到无效输入时,该函数将使用自定义 struct panic。恢复处理程序可以访问结构化的 panic 数据。
嵌套的 panic 和 recover
panic 和 recover 可以嵌套在函数调用中。此示例展示了 panic 如何通过多个函数调用进行复杂的传播。
package main
import "fmt"
func inner() {
fmt.Println("Entering inner")
panic("inner panic")
fmt.Println("Leaving inner")
}
func middle() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Middle recovered:", r)
panic("re-panicked in middle")
}
}()
inner()
}
func outer() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Outer recovered:", r)
}
}()
middle()
}
func main() {
fmt.Println("Calling outer")
outer()
fmt.Println("Returned normally from outer")
}
panic 源于 inner,在 middle 中被捕获并重新 panic,最后在 outer 中被捕获。这表明 panic 如何沿着调用堆栈向上传播。
来源
本教程通过实际的错误处理和恢复模式,介绍了 Go 中的 panic 函数。