W3Basic Logo

Go defer, panic, and recover

We use defer to delay the execution of instructions, panic to halt the execution of the program immediately and recover built-in function is used to recover from a panic.

In this chapter, we will look at new ways to handle errors in Go, through the use of the defer keyword and of the panic and recover functions.


defer

The defer keyword is used to delay the execution of an instruction until the end of the function.

In the following example, we have three print statements.

  • The Println that has defer executes at last before the function end.
  • The other two Println executes before in the defer statement.
package main

import "fmt"

func main() {

    // defer the execution of Println()
    defer fmt.Println("I am number 3")

    fmt.Println("I am number 1")
    fmt.Println("I am number 2")

}

Output

I am number 1
I am number 2
I am number 3

The most common use of defer is to close a file:

func main() {
    file, err := os.Open("file.txt")
    if err != nil {
        // handle the error
    }
    defer file.Close()

    // body of the function
}

This way, it is easy to check that the file is going to be closed when Compared with the following traditional code:

func main() {
    file, err := os.Open("file.txt")
    if err != nil {
        // handle the error
    }

    // body of the function

    file.Close()
}

If the main function returns before the file.Close() instruction is executed, or if an error occurs, the file will not be closed.

Multiple defer statements in Go

We can have multiple defer statements in a program. The execution order, in this case, would be LIFO (Last in, First Out). It means the last defer statement will get executed first.

In the following example, we have added defer to all three Println statements. Notice the output the last statement gets executed at first, and then the first statement gets executed at last.

package main

import "fmt"

func main() {

    defer fmt.Println("I am number 1")
    defer fmt.Println("I am number 2")
    defer fmt.Println("I am number 3")

}

Output

I am number 3
I am number 2
I am number 1

panic

The panic function is used to stop the execution of a function and to return it to the caller. The statements after the panic function will not be executed. It is similar to errors, but it is used as a last resort.

package main

import "fmt"

func Divide(a, b int) int {
    if b == 0 {
        panic("ERROR: cannot divide by zero")
    }
    return a / b
}

func main() {

    fmt.Println(Divide(4, 2))
    fmt.Println(Divide(4, 0))
    fmt.Println("Execution Completed")

}

Output

2
panic: ERROR: cannot divide by zero

The panic keyword in output indicates that the program is terminated due to panic, and it prints the relevant panic message along with it.

More Real World Example:

In the following example, if the file open fails for any reason, it creates panic and stops the execution of the code.

func OpenFile(name string) *os.File {
    file, err := os.Open(name)
    if err != nil {
        panic(err)
    }
    return file
}

recover

Finally, the recover built-in function is used to recover from a panic. Here is a trivial example to illustrate how it works:

func main() {
    var x := 0
    defer func() {
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    }()
    if x == 0 {
        panic("ERROR: x cannot be zero")
    }
}

In the above snippet, the recover function is called just before the function returns, and the error is printed rather than the program crashing.

But using panic and recover is not recommended if you can avoid them and implement the error interface.

© 2023 W3Basic. All rights reserved.

Follow Us: