Panic in Go
In this tutorial, we are going to discuss panic in Go language. In Go, panic
is a built-in function that stops the normal execution of the current goroutine and begins panicking.
What is Panic?
In the Go language, Panic is similar to the exception. This is meant to exit from a program in abnormal conditions. It can occur in a program in 2 ways
- Runtime error in the program
- By calling the panic function explicitly. This can be called by the programmer when the program cannot continue and it has to exit.
1. Runtime Error in the program
Runtime error in the program can happen in the below cases
- Calling a function on a nil pointer
- Out of bounds array access
- Sending on a closed channel
- Incorrect type assertion etc.
Let’s stop theory and see an example of runtime error caused by out of bounds array access.
package main
import "fmt"
func main() {
names := []string{"Ashok", "Sai", "Rama", "Seetha"}
print(names, 5)
}
func print(names []string, index int) {
fmt.Println(names[index])
}
Output
panic: runtime error: index out of range [5] with length 4
goroutine 1 [running]:
main.print(...)
/tmp/sandbox745973963/prog.go:11
main.main()
/tmp/sandbox745973963/prog.go:7 +0x1d
In the above example, we have a slice of length 4, and we are trying to access slice at index 5 in the print function.
Out of bound access is not allowed, and it will create panic, as seen from the output. Notice that in the output, there are two things
- The error message
- Stack trace of where the panic happened
Also there are many more cases in which runtime error can happen in a program. I am not going to mention all of them but you get the idea
Calling the panic function explicitly
In some of the cases where the panic function can be called explicitly by the programmer like,
- The function expected a valid argument, but instead, a nil argument was supplied. In such a case, the program cannot continue, and it will raise a panic for a nil argument passed
- Any other scenario in which the program cannot continue. etc.
Let’s see an example.
package main
import "fmt"
func main() {
names := []string{"Ashok", "Sai", "Rama", "Seetha"}
checkAndPrint(names, 5)
}
func checkAndPrint(names []string, index int) {
if index > (len(names) - 1) {
panic("Out of bound access for slice")
}
fmt.Println(names[index])
}
Output
panic: Out of bound access for slice
goroutine 1 [running]:
main.checkAndPrint(0xc0000a2f38, 0x4, 0x4, 0x5)
/tmp/sandbox582099440/prog.go:12 +0xea
main.main()
/tmp/sandbox582099440/prog.go:7 +0xb5
In the above example, we have a function named checkAndPrint that accepts a slice as an argument and an index. Then it checks whether the index passed is greater than the length of slice minus 1.
If it is, then it is out-of-bounds access for the slice, so it panics. If not, then it prints the value at that index. Again notice that in the output, there are two things.
- The error message
- Stack trace of where the panic happened
Panic with defer
When the panic is raised in a function, then the execution of that function is stopped, and any deferred function will be executed.
In fact a deferred function of all the function calls in the stack will also be executed until all the functions have returned. At that time, the program will exit, and it will print the panic message.
So if a defer function is present, then it will be executed, and the control will be returned to the caller function, which will again execute its defer function if present, and the chain goes on until the program exists.
package main
import "fmt"
func main() {
var name string
defer print()
if name == "" {
panic("Panic with Defer")
}
fmt.Println("After panic")
}
func print() {
fmt.Println("Welcome to waytoeasylearn")
}
Output
Welcome to waytoeasylearn
panic: Panic with Defer
goroutine 1 [running]: main.main()
/tmp/sandbox533301674/prog.go:9 +0x5b
In the above program, we have a defer function first, and then we manually create the panic. As you can see from the output, that defer function got executed as the below line is printed in the output.
Welcome to waytoeasylearn
Now let’s understand what happens when it happens in a program. Imagine a function call from the main function to f1 function to f2 function.
main->f1->f2
Controlflow
Now let’s say that panic happens in function f2, then below will be the sequence of events that will be happening.
- The execution of f2 will stop. Defer functions in f2 will be executed if present. Control will return to the caller, which is a function f1.
- f1 function will behave similarly as if panic happened in that function and after that call will return to the caller, which is the main function. Note that if there are more functions in between then, the process will continue up the stack in a similar way
- The main function will also behave as if panic happened in that function, and after that, the program will crash
- Once the program crashes, it will print the panic message along with this stack trace.
package main
import "fmt"
func main() {
f1()
}
func f1() {
defer fmt.Println("Defer in function f1")
f2()
fmt.Println("After painc in function f1")
}
func f2() {
var name string
defer fmt.Println("Defer in function f2")
if name == "" {
panic("Panic with Defer")
}
fmt.Println("After painc in function f2")
}
Output
Defer in function f2
Defer in function f1
panic: Panic with Defer
goroutine 1 [running]:
main.f2()
/tmp/sandbox580326332/prog.go:17 +0x95
main.f1()
/tmp/sandbox580326332/prog.go:10 +0x96
main.main()
/tmp/sandbox580326332/prog.go:6 +0x25
In the above program, panic happened in the f2 function like below.
panic("Panic with Defer")
and the defer function in f2 is called after that and it prints the below message
Defer in f2
Notice that as soon as the panic happens in the f2 function, its execution stops therefore below line if f2 never gets executed
fmt.Println("After painc in f2")
Control returns to f1, and it has a defer function. The defer gets executed, and it prints the below message.
Defer in f1
Control returns to the main function after that, and then the program crashes. The output prints the panic message along with the entire stack trace from main to f1 to f2.
That’s all about the Panic in Go language. If you have any queries or feedback, please write us email at contact@waytoeasylearn.com. Enjoy learning, Enjoy Go language.!!