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
函数。