Defer, Panic and Recover Control flow Concepts in Go
Introduction
Defer, Panic and Recover are essential concepts when developing Go applications. With the defer
function, you are able to call a function but prevent execution until some other functions are executed. If you are familiar with Python language, the defer
function is similar to finally
keyword in Python.
For your Go application to panic
, it has to come to a point where it cannot run anymore because it doesn't know what to do. This can be triggered by the compiler or manually in our code.
As for the recover
keyword, it is closely related with panic
. When a program enters a panic state we have an option to help it recover from that, we use the recover
keyword.
In this article, you will learn how defer
, panic
and recover
functions work, its properties, and use-cases.
Prerequisites
- Basic knowledge of Golang
Defer
The defer
statement enables you to prevent the execution of a function until a later time, depending on what you are trying to accomplish.
Using a real-world example, growing up every guy has the ability to grow beards but that ability is held for some reason till you are older. Basically, that is how defer
works.
Properties
- Defer statement doesn’t run a function, it runs the function call.
- It follows last in, first out order, i.e., the last
defer
statement that is called will be the first to be executed.
How to use Defer
package main
import("fmt")func main() {
fmt.Println("one")
defer fmt.Println("three")
fmt.Println("two")}
output:
one
two
three
Notice that three
was printed last. This is because any statement that is preceded by the defer
keyword isn’t invoked until the end of the function in which defer
was used.
package main
import("fmt")func main() {
defer fmt.Println("one")
defer fmt.Println("two")
defer fmt.Println("three")}
output:
three
two
one
As stated in the property above, the first defer statement to be called is the last to be executed.
Panic
panic
is a built-in function that stops the control flow of your program. This can be done by the compiler or added manually to your code flow.
We use panic statements when your application enters a state that it cannot recover from. Example: Trying to divide a number by 0.
They occur when the program can’t continue at all.
Properties
- Panics happen after a deferred statement is executed.
- the program ends after the panic statement is run.
How to use Panic
package main
import "fmt"func main(){
fmt.Println("one")
defer fmt.Println("three")
panic("a panic happened")
fmt.Println("four")}
Output:
one
three
panic: a panic happened
As you can see above, because of the panic we invoked in the code compiler didn’t execute the rest of the program.
Another example:
package mainimport "fmt"func main() {
x := 0
y := 20
fmt.Println(y/x)
}
Output:
panic: runtime error: integer divide by zero
goroutine 1 [running]:
main.main()
/tmp/sandbox064477089/prog.go:8 +0x11
The output above shows that instead of the defer statement to be run last, it is executed first before the panic happened. Note: the Go compiler can also invoke panic.
Recover
recover
function is used to recover function from panic
. Recover is only useful inside deferred functions. In a normal execution, a call to recover will returnnil
and have no other effect. Arecover
function should always be called inside a defer
function because the deferred function does not stop its execution if the program panics, so the recover
function stops the panicking.
Properties
- Recovery statements are used to come out of a panic
- Useful inside deferred functions. This is because when an application panics, it no longer executes the rest of the program except for deferred functions.
How to use Recover
package mainimport "fmt"func main() {
x := 0
y := 20
printAllOperations(x, y)
}func printAllOperations(x int, y int) {defer func() {
// defer function to escape the panic when y/x runs
if r := recover(); r != nil {
fmt.Printf("Recovering from panic in printAllOperations error is: %v \n", r)
fmt.Println("Proceeding to alternative flow skipping division.")
printOperationsSkipDivide(x, y)
}
}()sum, divide, multiply := x+y, y/x, x*y
fmt.Printf("sum=%v, divide=%v, multiply=%v \n", sum, divide, multiply)
}func printOperationsSkipDivide(x int, y int) {
sum, multiply := x+y, y*x
fmt.Printf("sum=%v, multiply=%v \n", sum, multiply)
}
output:
Recovering from panic in printAllOperations error is: runtime error: integer divide by zero
Proceeding to alternative flow skipping division.
sum=20, multiply=0
20/0
caused panic in the Go compiler so it invoked the defer function which printed the results of the rest of the results
Conclusion
In this tutorial, we are able to figure out how the defer, recover, and panic functions are used in a Golang application. I hope this guide helps you write better Golang with those functions.