Open In App

Go - Defer, Panic, and Recover

Last Updated : 05 Feb, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Error handling is crucial for writing robust and maintainable code in Go. It provides three key tools:

  • defer: Delays function execution until the surrounding function completes.
  • panic: Immediately stops the program when a critical error occurs.
  • recover: Regains control after a panic to prevent a crash.

Go treats errors as values, usually returned as the last function result. When an error is too severe, panic and recover help manage unexpected failures.

1. defer in Go

The defer statement is used to ensure that a function call is executed later in the program’s execution, usually for cleanup purposes. This is particularly useful for releasing resources like file handles, database connections, or mutex locks.

How defer Works?

When you use defer, the deferred function is pushed onto a stack. When the surrounding function returns, the deferred functions are executed in Last In, First Out (LIFO) order.

Example:

package main
import "fmt"

func main() {
// defer the execution of Println() function
defer fmt.Println("Three")

fmt.Println("One")
fmt.Println("Two")
}

Output:

One
Two
Three

In this example, the fmt.Println("Three") statement is deferred, so it executes after fmt.Println("One") and fmt.Println("Two").

Multiple defer Statements

When multiple defer statements are used, they are executed in LIFO order.

Example:

package main
import "fmt"

func main() {
defer fmt.Println("One")
defer fmt.Println("Two")
defer fmt.Println("Three")
}

Output:

Three
Two
One

Here, the last defer statement (fmt.Println("Three")) is executed first, and the first defer statement (fmt.Println("One")) is executed last.

2. Golang panic

The panic statement is used to immediately stop the execution of a program when an unrecoverable error occurs. When a panic is triggered, the program starts unwinding the stack, running any deferred functions along the way, and then crashes with an error message.

How panic Works?

When panic is called, the normal flow of the program is interrupted. The program prints a panic message, followed by a stack trace, and then terminates.

Example: Basic panic Usage

package main
import "fmt"

func main() {
fmt.Println("Help! Something bad is happening.")
panic("Ending the program")
fmt.Println("Waiting to execute") // This line will not execute
}

Output:

Help! Something bad is happening.
panic: Ending the program

In this example, the program terminates when it encounters the panic statement, so the line fmt.Println("Waiting to execute") is never executed.

Example: 

Let’s look at a more practical example where panic is used to handle division by zero.

Go
package main
import "fmt"

func division(num1, num2 int) {
    // if num2 is 0, program is terminated due to panic
    if num2 == 0 {
        panic("Cannot divide a number by zero")
    } else {
        result := num1 / num2
        fmt.Println("Result: ", result)
    }
}

func main() {
    division(4, 2)
    division(8, 0) // This will cause a panic
    division(2, 8) // This line will not execute
}

Output:

Result:  2
panic: Cannot divide a number by zero

Here, the program panics when it attempts to divide by zero, and the subsequent function call (division(2, 8)) is never executed.

3. Recover

While panic is used to terminate a program, recover is used to regain control after a panic has occurred. This allows the program to handle the error gracefully instead of crashing.

The recover function is used inside a deferred function to catch the panic message and resume normal execution. If recover is called outside of a deferred function, it has no effect.

Example: Using recover to Handle panic

Go
package main
import "fmt"

// recover function to handle panic
func handlePanic() {
    // detect if panic occurs or not
    a := recover()

    if a != nil {
        fmt.Println("RECOVER:", a)
    }
}

func division(num1, num2 int) {
    // execute the handlePanic even after panic occurs
    defer handlePanic()

    // if num2 is 0, program is terminated due to panic
    if num2 == 0 {
        panic("Cannot divide a number by zero")
    } else {
        result := num1 / num2
        fmt.Println("Result:", result)
    }
}

func main() {
    division(4, 2)
    division(8, 0) // This will cause a panic, but it will be recovered
    division(2, 8)
}

Output:

Result: 2
RECOVER: Cannot divide a number by zero
Result: 0

In this example, the handlePanic function is deferred inside the division function. When a panic occurs, handlePanic is called, and the program recovers from the panic instead of terminating.

Key Points About recover

  1. Deferred Executionrecover only works inside deferred functions. This ensures that it is called during the stack unwinding process after a panic.
  2. Panic Message: The recover function returns the value passed to panic, allowing you to log or handle the error message.
  3. Graceful Recovery: Using recover allows your program to continue executing even after a critical error.

When to Use deferpanic, and recover

  • defer: Use defer for cleanup tasks, such as closing files, releasing locks, or logging. It ensures that resources are properly managed, even if an error occurs.
  • panic: Use panic for unrecoverable errors, such as invalid input or system failures, where continuing execution would cause more harm.
  • recover: Use recover to handle panics gracefully, especially in long-running applications like servers, where crashing is not an option.

Conclusion

Go’s defer, panic, and recover help manage errors and resource cleanup effectively:

  • Use defer for cleanup and releasing resources.
  • Use panic for critical errors that should stop execution.
  • Use recover to handle panics and prevent crashes.

By mastering these, you can write robust and maintainable Go programs.