Chapter 12 - Recovering from Failure

Exercise 2: panic and recover

Go through the following code samples, and predict what their output will be. No need to predict all the details of the stack traces; focus on determining which fmt.Println calls will get made, and in what order.

Solution

Example 1

package main

import "fmt"

func main() {
	fmt.Println("a")
	panic("oh no")
	// This call never gets made.
	fmt.Println("b")
}

Output:

a
panic: oh no

goroutine 1 [running]:
main.main()
	/tmp/sandbox493149858/prog.go:7 +0xa0

Example 2

package main

import "fmt"

func myFunction() {
	// Even though the next line panics, this call gets
	// made when myFunction exits.
	defer fmt.Println("b")
	panic("oh no")
}

func main() {
	fmt.Println("a")
	myFunction()
}

Output:

a
b
panic: oh no

goroutine 1 [running]:
main.myFunction()
	/tmp/sandbox836036355/prog.go:7 +0xa0
main.main()
	/tmp/sandbox836036355/prog.go:12 +0xa0

Example 3

package main

import "fmt"

func myFunction() {
	panic("oh no")
	// This call is never made because `myFunction`
	// exits as soon as the program panics.
	fmt.Println(recover())
}

func main() {
	fmt.Println("a")
	myFunction()
	fmt.Println("b")
}

Output:

a
panic: oh no

goroutine 1 [running]:
main.myFunction()
	/tmp/sandbox950318916/prog.go:6 +0x40
main.main()
	/tmp/sandbox950318916/prog.go:12 +0xa0

Example 4

package main

import "fmt"

func otherFunction() {
	// This runs when the deferred function call is made.
	fmt.Println("c")
	// This recovers from the panic and prints the panic
	// message.
	fmt.Println(recover())
}

func myFunction() {
	// This call gets made when myFunction panics.
	defer otherFunction()
	panic("oh no")
	// Execution does not resume here, because this
	// function exited due to the panic.
	fmt.Println("d")
}

func main() {
	fmt.Println("a")
	myFunction()
	// Execution resumes here after recovering.
	fmt.Println("b")
}

Output:

a
c
oh no
b

Because the program recovered from the panic, it doesn’t exit early, and so no stack trace is printed.