Hands-On System Programming with Go
上QQ阅读APP看书,第一时间看更新

Defer, panic, and recover

A very important keyword that hides a lot of complexity but makes it possible to execute many operations easily is defer. This is applied to a function, method, or closure execution and makes the function it precedes execute before the function returns. A common and very useful usage is closing resources. After opening the resource successfully, a deferred close statement will ensure that it is executed independently of the exit point, as shown in the following code:

f, err := os.Open("config.txt")
if err != nil {
return err
}
defer f.Close() // it will be closed anyways

// do operation on f

During a function's lifetime, all the deferred statements are added to a list and before exiting, they are executed in reverse order, from the last to the first defer.

These statements are executed even when there's a panic, which is why a deferred function with a recover call can be used to intercept a panic in the respective goroutine and avoid the panic that would kill the application otherwise. As well as a manual call to the panic function, there is a set of operations that will cause a panic, including the following:

  • Accessing a negative or non-existent array/slice index (index out of range)
  • Dividing an integer by 0
  • Sending to a closed channel
  • Dereferencing on a nil pointer (nil pointer)
  • Using a recursive function call that fills the stack (stack overflow)

Panic should be used for errors that are not recoverable, which is why errors are just values in Go. Recovering a panic should be just an attempt to do something with that error before exiting the application. If an unexpected problem occurs, it's because it hasn't been handled correctly or some checks are missing. This represents a serious issue that needs to be dealt with, and the program needs to change, which is why it should be intercepted and dismissed.