Panic and Recover Statement in Golang
Overview
In this article, we'll take a look at how to handle errors using a built-in function such as Panic statement and Recover statement, we will see how we can extract useful information from the errors we are receiving and the best practices to implement recover and panic statement. We will also see what is the need for a defer statement with recover.
What is a Panic Statement in Golang?
When we write in Golang, we often notice that if there is an abnormal condition, we get the output as "panic" because it's a way in Golang to handle abnormal conditions. , For example,, if a program is unable to continue its execution, this "panic" will help to terminate that condition and stop the program at that time. In Golang, panic occurs during runtime. , For example,, if we want to access an index that is not in the range, the code will start panicking.
Here are some key points about panic in Go:
- A panic is triggered by calling the built-in "panic" function and can be caused by any runtime error that the program cannot handle.
- When panic occurs, the program will stop executing and begin unwinding the stack of goroutines. This means that the program will exit all the functions that were called up until the panic.
- If the program reaches the top-level function of the main goroutine without finding a way to handle the panic, the program will exit with a non-zero exit status.
- Panic is a powerful tool for debugging, it helps to identify the point where the error occurred and the call stack that led to the error, allowing the developer to understand what went wrong and fix it.
Signature of Panic Statement
The signature of the built-in Panic Function is provided below,
When the programme ends, the argument given to the panic function will be displayed.
When to Use Panic?
The developer states that we should avoid using "panic" in our codebase and instead use errors wherever possible. It should consider only when the program is not able to continue execution.
Use Cases of Panic Statement
For Panic, there are mainly two valid use cases:
1. Developer Error:
Assume we have a function that accepts a pointer as a parameter and is called with a nil argument. In this scenario, we should be concerned since calling a method with nil arguments when it was expecting a real reference is a logical mistake. Consider the example below which occurred due to a programmer's mistake,
For Example:
Output:
Explanation:
- In the above code, the main function creates a variable empName of the typed string with a value of Amisha and a variable age of type int with a value of 75. It then calls the employee function passing in the address of empName and the value of age as arguments.
- When the employee function is called, it checks if the value of age is greater than 15 and since 75 is greater than 15, it will trigger the panic with the message Age cannot be greater than retirement age.
- This panic will cause the program to stop executing and begin unwinding the stack of goroutines until it reaches a point where the panic can be handled. If the panic is not handled, the program will exit with a non-zero exit status
2. An Unrecoverable Mistake in which the Application Cannot Simply Continue Running:
, For example,, if a web server fails to respond to a required request from the client side. At that time, it's reasonable to panic, as there is nothing else to do if the request fails.
For Example:
Output:
Explanation:
- In the above code, a map called "emp" uses the "make" function. It assigns the value 20 to the key "Scaler" and the value 23 to the key "Golang".
- It then tries to print the value of the key 20 which is not present in the map and it will return a zero value which is nil in this case.
- The code will cause panic since the key 20 does not exist on the map.
Examples:
Output:
Another Example:
Output:
Explanation:
- In the above code, The first line uses the "fmt" package to print the string "Help! It's not going the right way." to the console.
- The second line triggers a panic with the message "Ok, I Ending the program".
- The third line uses the "fmt" package to print the string "Waiting to execute" to the console.
- When a panic is triggered, the program will stop executing and begin unwinding the stack of goroutines until it reaches a point where the panic can be handled. Since the panic is not handled in this code, the program will exit and the third line of code which is fmt.Println("Waiting to execute")" will never be executed.
Defer Call During a Panic
The panic stops the flow but before that, it executes the deferred function calls.
- Defer Statement: It is a technique for deferring a function by placing it on an executed stack once the function containing the defer statement has completed, either normally by executing a return statement or unnaturally by panicking.
- Deferred Functions: Deferred Functions are then run in the reverse order that they were deferred. We use the deferred function by using the defer keyword in the program.
- The Function is Executed Last:. That means, the function will be run last after all other programmes have been executed.
Defer Function Example:
Output:
Explanation:
- In The above code, The first line uses the "defer" keyword to postpone the execution of the "fmt.Println("Scaler")" function until the surrounding function (main) returns.
- The "defer" keyword in Go allows you to schedule a function call to be executed at a later time, which is typically when the surrounding function returns. It's useful for tasks such as cleaning up resources or logging.
- In this case, the "fmt.Println("Scaler")" function is executed last after the main function returns, which is after the execution of the second and third line of code.
After that we use the deferred function with panic:
Output:
Explanation:
- In this example, the cleanup function is defined and it uses the fmt package to print the string Cleaning up resources... to the console.
- The main function uses the defer keyword to schedule the execution of the cleanup function to be executed at a later time and the program triggers a panic with the message Oh no, something went wrong! which will cause the program to stop executing and begin unwinding the stack of goroutines until it reaches a point where the panic can be handled.
- Since the panic is not handled in this code, the program will exit and the deferred function cleanup will be executed before the program exits, allowing you to clean up resources or perform any other necessary cleanup tasks before the program exits.
In simple words, using defer with "panic" in Golang allows you to schedule a function call to be executed even when the program panics and exits, allowing you to perform necessary cleanup or logging tasks before the program exits.
What is a Recover Statement in Golang?
In some situations, like in panic statement immediately terminates the program but in some scenarios, it might be important to complete its execution and get some desired output.
The recover() function is a built-in function that allows you to exit a panicked go thread. The method must be implemented within a deferred function to be run before the panic terminates the thread.
Signature of Recover Statement
When to Use the Recover Statement?
- The Recover is useful when we are using it inside the deferred function. As it stops the panicking sequence by restoring to normal execution.
- If we use recover outside of the defer function it will not able to stop panicking.
Some more cases you can consider such:
- When you want to prevent the program from crashing and instead handle the panic in a controlled way. , For example,, you can use recover to log the error and display a friendly error message to the user.
- When you want to test the behavior of your program when it panics.
Use Cases of Recover Statement
Calls to Reduce Error Checks: It can be used to reduce the error checks in the code.
Examples:
Output:
Explanation:
- In the above code, the defFunc function is a simple function that uses the fmt package to print the string This is a deferred function to the console. And it also has a recovery statement inside, which is used to recover from panic if one occurs.
- In the main function, triggers a panic with the message Not working!! which will cause the program to stop executing and begin unwinding the stack of goroutines until it reaches a point where the panic can be handled.
- But the panic function is not handled program will exit, but defFunc has a recover statement inside, it will recover from the panic and print the message Recovered from the panic that is: Not working!! to the console which shows how to handle panic using recover statement.
Another Example:
Output:
Explanation:
- In this example, the divide(a, b int) function takes two integer parameters and returns an integer. If the second parameter is 0, the function panics with the message "Cannot divide by zero!".
- This panic is caught by the deferred function which uses the recover() function to catch the panic and prints a message indicating that the panic was recovered.
- When the first call to divide(5, 2) is made, the function executes without panicking and returns the result 2.
- But when the second call to divide(5, 0) is made, the function panics and the deferred function using recover() catches the panic and prints "Recovered from panic: Cannot divide by zero!".
Stack Trace Error After Recover
When we recover from panic, we lose the stack trace(a place where panic is produced) about the panic. There is a way to get the stack trace after recover using the PrintStack function of the Debug package.
Let's see the example:
Output:
Explanation:
- In the above code, we imported a debug library and for printing stack trace we used debug.PrintStack().
- As the above output stated that panic is recovered recovered from runtime error: last name cannot be nil is printed as output.
- returned normally from main deferred call in mainis printed after the panic has recovered.
Conclusion:
- Panic Statement: It is a way to terminate the program if it's not able to recover from some major errors.
- Recover Statement: The panic statement ends the programme instantly. However, sometimes it is occasionally necessary for a programme to finish its execution and produce some essential results,recover is used to print those necessary results. It is used to come out of panic.
- The recover function should be used only in exceptional cases where the program cannot continue executing due to a critical error, , for example,, running out of memory, or any other issue that prevents the normal execution of the program.
- Defer: It allows us to run all programs or execute all programs before it and at last defer function will be executed.
- However, we should avoid panic/recovery as it's less efficient and less Go-idiomatic.