Chapter 12 - Recovering from Failure
Exercise 1: defer
We need to be sure our Camp
function calls the Fire
value’s Extinguish
method before the program exits. But right now, Camp
is returning early due to an error, before Extinguish
can be called.
We don’t want to leave a lit Fire
unattended in the forest! Revise the Camp
function so that Extinguish
is always called, even if Camp
returns early.
package main
import "fmt"
type Fire struct {
lit bool
}
func (f Fire) Light() {
f.lit = true
fmt.Println("Fire lit:", f.lit)
}
func (f Fire) Extinguish() {
f.lit = false
fmt.Println("Fire lit:", f.lit)
}
func Camp() error {
var fire Fire
fire.Light()
return fmt.Errorf("spotted a bear")
fmt.Println("Toasting marshmallows")
fire.Extinguish()
return nil
}
func main() {
err := Camp()
if err != nil {
fmt.Println(err)
}
}
Actual Output:
Fire lit: true
Error: spotted a bear
Desired Output:
Fire lit: true
Fire lit: false
Error: spotted a bear
When you’re ready, have a look at our solution.
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")
fmt.Println("b")
}
Example 2
package main
import "fmt"
func myFunction() {
defer fmt.Println("b")
panic("oh no")
}
func main() {
fmt.Println("a")
myFunction()
}
Example 3
package main
import "fmt"
func myFunction() {
panic("oh no")
fmt.Println(recover())
}
func main() {
fmt.Println("a")
myFunction()
fmt.Println("b")
}
Example 4
package main
import "fmt"
func otherFunction() {
fmt.Println("c")
fmt.Println(recover())
}
func myFunction() {
defer otherFunction()
panic("oh no")
fmt.Println("d")
}
func main() {
fmt.Println("a")
myFunction()
fmt.Println("b")
}
Here are the solutions.