In general, we use errors to handle the abnormal conditions in programming languages. But there are some unavoidable situations like accessing a nil pointer or accessing an array index which is out of array boundary. In those situations, the program cant execute further and it gets terminate and that situation is called a panic situation in coding world. Lets see a panic example.
import “fmt”
func aboutme(name *string, age int) {
fmt.Printf(“My name is %s and my age is %d\n”, *name, age)
}
func main() {
name1 := “sus”
aboutme(&name1, 10)
aboutme(nil, 20)
fmt.Println(“returned normally from main”)
}
My name is sus and my age is 10
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x4930d9]
goroutine 1 [running]:
main.aboutme(0x0, 0x14)
/home/rjio/Go/src/MyGo/go.go:6 +0x29
main.main()
/home/rjio/Go/src/MyGo/go.go:12 +0x63
exit status 2
As above, we can see, when first time we have called the aboutme() function with &name1, it has executed properly without any error. But when it executes 2nd time with name argument as nil, it has got a panic and the program execution terminates with a panic error and some more info like “invalid memory address or nil pointer dereference”
Also, just below you can see the stack trace with line numbers.
The first entry in the stack is (main.aboutme(0x0, 0x14), prog.go:6) i,e line number 6 and within function aboutme()
The 2nd entry in the stack is (main.main(), prog.go:12), i,e 12 is the line number in the prog.gm and within function main(), form where the previous stack has been called.
Check another example, where we are trying to access the index which is out of array boundary.
package main
import “fmt”
func main() {
names := [3]string{“Alpha”, “Beta”, “Gama”}
fmt.Println(names[1])
fmt.Println(names[9])
}
./prog.go:8:19: invalid array index 9 (out of bounds for 3-element array)
Build-in panic() function:-
As above a panic may occur by the program itself at run time.
One more way is, as a programmer you can explicitly call to the built-in panic() function to handle some of the worst-case scenarios in the Go program or for an unrecoverable error from where we want to terminate the program.
Lets modify the above program using the build-in panic() function.
package main
import “fmt”
func aboutme(name *string, age int) {
if name == nil {
panic(“runtime error: name cannot be nil”)
}
fmt.Printf(“My name is %s and my age is %d\n”, *name, age)
}
func main() {
name1 := “SUSANTA”
aboutme(&name1, 10)
aboutme(nil, 20)
fmt.Println(“returned normally from main”)
}
My name is SUSANTA and my age is 10
panic: runtime error: name cannot be nil
goroutine 1 [running]:
main.aboutme(0x0, 0x14)
/tmp/sandbox572660608/prog.go:7 +0x111
main.main()
/tmp/sandbox572660608/prog.go:15 +0x65
AS in above example, here we have provided a more useful info to the panic() function like “name cannot be nil”. Hence it become easy to debug by seeing the error logs.
Defer statements with panic():—
Whenever we defer statements within a panic function, the defer statements are always executed, as those defer statements are already pushed into LIFO-stack before the panic. Lets try with an example.
package main
import “fmt”
func aboutme(name *string, age int) {
defer fmt.Println(“Defer statement in aboutme()”)
if name == nil {
panic(“runtime error: name cannot be nil”)
}
fmt.Printf(“My name is %s and my age is %d\n”, *name, age)
}
func main() {
defer fmt.Println(“Defer statement in main()”)
name1 := “SUSANTA”
aboutme(&name1, 10)
aboutme(nil, 20)
fmt.Println(“returned normally from main”)
}
My name is SUSANTA and my age is 10
Defer statement in aboutme()
Defer statement in aboutme()
Defer statement in main()
panic: runtime error: name cannot be nil
goroutine 1 [running]:
main.aboutme(0x0, 0x14)
/tmp/sandbox931434933/prog.go:7 +0x1ca
main.main()
/tmp/sandbox931434933/prog.go:16 +0xdc