Golang recover 函数
最后修改时间 2025 年 5 月 8 日
本教程将介绍如何在 Go 中使用内置的 recover 函数。我们将通过实际的正确错误处理示例来讲解 panic 恢复基础知识。
recover 函数用于重新获得一个正在 panic 的 goroutine 的控制权。它会停止 panic 序列并返回传递给 panic 的值。Recover 仅在 defer 的函数中有用。
在 Go 中,recover 与 panic 和 defer 配合使用,以处理异常情况。它允许在意外错误后进行优雅的关闭或继续执行。
基本的 panic 恢复示例
recover 最简单的用法是捕获 panic 并阻止程序崩溃。此示例演示了基本的 panic 恢复。
注意: Recover 必须在 defer 的函数中调用。
package main
import "fmt"
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
panic("something went wrong")
fmt.Println("This line won't be executed")
}
当发生 panic 时,defer 的函数会调用 recover。在 defer 的函数完成后,程序将继续执行。
从零除恢复
我们可以使用 recover 来处理运行时错误,例如零除。此示例展示了数学运算中的实际错误恢复。
package main
import "fmt"
func safeDivide(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("division error: %v", r)
}
}()
result = a / b
return result, nil
}
func main() {
res, err := safeDivide(10, 0)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", res)
}
}
safeDivide 函数可以从零除 panic 中恢复。它将 panic 转换为常规的错误返回值。
在 goroutine 中恢复
每个 goroutine 都需要自己的 panic 恢复。此示例展示了如何正确处理并发代码中的 panic。
package main
import (
"fmt"
"time"
)
func worker() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Worker recovered:", r)
}
}()
fmt.Println("Worker started")
time.Sleep(1 * time.Second)
panic("worker panic")
fmt.Println("Worker finished")
}
func main() {
go worker()
time.Sleep(2 * time.Second)
fmt.Println("Main function completed")
}
工作 goroutine 有自己的恢复机制。由于有适当的恢复,panic 不会影响主 goroutine。
使用日志记录进行恢复
我们可以将 recover 与详细的错误日志记录结合起来。此示例演示了带堆栈跟踪的高级 panic 恢复。
package main
import (
"fmt"
"runtime/debug"
)
func riskyOperation() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
fmt.Println("Stack trace:")
debug.PrintStack()
}
}()
var nilMap map[string]string
nilMap["key"] = "value" // Will panic
}
func main() {
riskyOperation()
fmt.Println("Program continues after recovery")
}
恢复处理程序会记录 panic 值和堆栈跟踪。这有助于调试,同时允许程序继续运行。
在 Web 服务器中恢复
Web 服务器应从 panic 中恢复以保持可用性。此示例展示了 HTTP 处理程序中的 panic 恢复。
package main
import (
"fmt"
"net/http"
)
func panicHandler(w http.ResponseWriter, r *http.Request) {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in handler:", r)
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Internal server error")
}
}()
panic("handler panic")
}
func main() {
http.HandleFunc("/", panicHandler)
fmt.Println("Server started on :8080")
http.ListenAndServe(":8080", nil)
}
HTTP 处理程序可以从 panic 中恢复并返回适当的错误响应。这可以防止整个服务器因单个请求而崩溃。
来源
本教程通过在各种场景下进行 panic 恢复的实际示例,介绍了 Go 中的 recover 函数。