In Go, panic
and recover
provide a way to handle unexpected errors and control the flow of a program when encountering critical issues. While they should be used sparingly, understanding how to effectively use panic
and recover
can help in building robust applications that handle catastrophic errors gracefully.
recover
is typically used within deferred functions.Using panic
should be reserved for situations where the program cannot continue running safely, such as when encountering a critical error that indicates a bug or corrupt state.
gopackage main
import (
"fmt"
)
func divide(a, b int) int {
if b == 0 {
panic("division by zero")
}
return a / b
}
func main() {
fmt.Println(divide(10, 2)) // Output: 5
fmt.Println(divide(10, 0)) // This will cause a panic
}
In this example, calling divide(10, 0)
causes a panic due to division by zero. The program will print the panic message and then terminate.
To avoid program crashes in critical sections, use recover
within a deferred function. This allows you to handle the panic and resume normal execution.
gopackage main
import (
"fmt"
)
func safeDivide(a, b int) int {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
return divide(a, b)
}
func divide(a, b int) int {
if b == 0 {
panic("division by zero")
}
return a / b
}
func main() {
fmt.Println(safeDivide(10, 2)) // Output: 5
fmt.Println(safeDivide(10, 0)) // This will print the recovery message
fmt.Println("Program continues running...")
}
In this example, the safeDivide
function uses a deferred function to recover from any panic that occurs during the call to divide
. If a panic occurs, recover
captures it, prints a message, and allows the program to continue running.
panic
for truly unrecoverable errors that indicate a bug or corrupt state. Do not use it for ordinary error handling.recover
in deferred functions to handle panics gracefully, especially in critical sections where you want the program to continue running.defer
to ensure resources are cleaned up properly even in the event of a panic.gopackage main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
http.Error(w, fmt.Sprintf("Internal Server Error: %v", err), http.StatusInternalServerError)
log.Printf("Recovered from panic: %v", err)
}
}()
if r.URL.Path == "/panic" {
panic("example panic")
}
fmt.Fprintf(w, "Hello, World!")
})
log.Println("Starting server on :8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatalf("Server failed to start: %v", err)
}
}
In this web server example, the handler function for the root path uses a deferred function to recover from any panics that occur during request processing. If a panic occurs, it responds with a 500 Internal Server Error and logs the panic message.
Using panic
and recover
effectively in Go allows you to handle catastrophic errors gracefully and ensure your application can recover from unexpected states. By following best practices and using these features judiciously, you can build more robust and resilient applications.