如何使用
panic一般跟recover、defer结合使用。当panic触发异常,当前函数会停止执行,然后执行当前函数中所有的defer。
func main() {
defer fmt.Println("Defer: This will be printed")
fmt.Println("Start")
panic("Something went wrong!")
fmt.Println("End") // 这行代码不会执行
}
注意:
如果没有捕获panic的报错,程序会崩溃并输出堆栈信息。
如何捕获panic
go提供了recover来捕获panic的错误,避免程序崩溃。基本使用如下:
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("捕获到 panic:", r)
}
}()
// 触发 panic
panic("发生严重错误!")
}
多层调用栈中的捕获
如果 panic 发生在嵌套调用的函数中,只要在调用链的某个 defer 中调用 recover(),即可拦截 panic。
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Main 捕获到 panic:", r)
}
}()
fmt.Println("执行 main")
riskyOperation()
}
func riskyOperation() {
defer fmt.Println("riskyOperation 的 defer")
fmt.Println("执行 riskyOperation")
panic("子函数 panic")
}
recover捕获后错误后,如何恢复运行的
recover 后程序会继续执行:捕获 panic 后,程序从 recover 所在的 defer 函数之后继续运行。
原函数的后续代码不会执行:触发 panic 后的代码(如 fmt.Println(“End”))会被跳过。
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("捕获到 panic:", r)
}
}()
fmt.Println("Start")
panic("Panic Here")
fmt.Println("End") // 这行不会执行
}
使用注意事项
-
recover 必须在 defer 中调用:否则无法捕获 panic。
// 错误示例:recover 不在 defer 中 func main() { if r := recover(); r != nil { // 无效! fmt.Println("无法捕获") } panic("error") }
-
避免滥用 panic 和 recover:
Go 的设计哲学是显式错误处理(通过返回值),panic 应仅用于不可恢复的错误(如程序启动依赖缺失)。 -
资源清理:
即使发生 panic,defer 仍会执行,因此可以在 defer 中释放资源(如关闭文件、解锁)。
使用场景
当程序发生严重错误,例如空指针、数组越界、程序初始化失败等情景下。
一般业务场景里的报错,例如http、请求超时,都建议通过在接口中额外传出一个error返回值,然后业务根据该返回值进行异常处理。