| <!--{ |
| "Title": "Defer, Panic, and Recover", |
| "Template": true |
| }--> |
| |
| <p> |
| Go has the usual mechanisms for control flow: if, for, switch, goto. It also |
| has the go statement to run code in a separate goroutine. Here I'd like to |
| discuss some of the less common ones: defer, panic, and recover. |
| </p> |
| |
| <p> |
| A <b>defer statement</b> pushes a function call onto a list. The list of saved |
| calls is executed after the surrounding function returns. Defer is commonly |
| used to simplify functions that perform various clean-up actions. |
| </p> |
| |
| <p> |
| For example, let's look at a function that opens two files and copies the |
| contents of one file to the other: |
| </p> |
| |
| {{code "/doc/progs/defer.go" `/func CopyFile/` `/STOP/`}} |
| |
| <p> |
| This works, but there is a bug. If the call to os.Create fails, the |
| function will return without closing the source file. This can be easily |
| remedied by putting a call to src.Close before the second return statement, |
| but if the function were more complex the problem might not be so easily |
| noticed and resolved. By introducing defer statements we can ensure that the |
| files are always closed: |
| </p> |
| |
| {{code "/doc/progs/defer2.go" `/func CopyFile/` `/STOP/`}} |
| |
| <p> |
| Defer statements allow us to think about closing each file right after opening |
| it, guaranteeing that, regardless of the number of return statements in the |
| function, the files <i>will</i> be closed. |
| </p> |
| |
| <p> |
| The behavior of defer statements is straightforward and predictable. There are |
| three simple rules: |
| </p> |
| |
| <p> |
| 1. <i>A deferred function's arguments are evaluated when the defer statement is |
| evaluated.</i> |
| </p> |
| |
| <p> |
| In this example, the expression "i" is evaluated when the Println call is |
| deferred. The deferred call will print "0" after the function returns. |
| </p> |
| |
| {{code "/doc/progs/defer.go" `/func a/` `/STOP/`}} |
| |
| <p> |
| 2. <i>Deferred function calls are executed in Last In First Out order |
| </i>after<i> the surrounding function returns.</i> |
| </p> |
| |
| <p> |
| This function prints "3210": |
| </p> |
| |
| {{code "/doc/progs/defer.go" `/func b/` `/STOP/`}} |
| |
| <p> |
| 3. <i>Deferred functions may read and assign to the returning function's named |
| return values.</i> |
| </p> |
| |
| <p> |
| In this example, a deferred function increments the return value i <i>after</i> |
| the surrounding function returns. Thus, this function returns 2: |
| </p> |
| |
| {{code "/doc/progs/defer.go" `/func c/` `/STOP/`}} |
| |
| <p> |
| This is convenient for modifying the error return value of a function; we will |
| see an example of this shortly. |
| </p> |
| |
| <p> |
| <b>Panic</b> is a built-in function that stops the ordinary flow of control and |
| begins <i>panicking</i>. When the function F calls panic, execution of F stops, |
| any deferred functions in F are executed normally, and then F returns to its |
| caller. To the caller, F then behaves like a call to panic. The process |
| continues up the stack until all functions in the current goroutine have |
| returned, at which point the program crashes. Panics can be initiated by |
| invoking panic directly. They can also be caused by runtime errors, such as |
| out-of-bounds array accesses. |
| </p> |
| |
| <p> |
| <b>Recover</b> is a built-in function that regains control of a panicking |
| goroutine. Recover is only useful inside deferred functions. During normal |
| execution, a call to recover will return nil and have no other effect. If the |
| current goroutine is panicking, a call to recover will capture the value given |
| to panic and resume normal execution. |
| </p> |
| |
| <p> |
| Here's an example program that demonstrates the mechanics of panic and defer: |
| </p> |
| |
| {{code "/doc/progs/defer2.go" `/package main/` `/STOP/`}} |
| |
| <p> |
| The function g takes the int i, and panics if i is greater than 3, or else it |
| calls itself with the argument i+1. The function f defers a function that calls |
| recover and prints the recovered value (if it is non-nil). Try to picture what |
| the output of this program might be before reading on. |
| </p> |
| |
| <p> |
| The program will output: |
| </p> |
| |
| <pre>Calling g. |
| Printing in g 0 |
| Printing in g 1 |
| Printing in g 2 |
| Printing in g 3 |
| Panicking! |
| Defer in g 3 |
| Defer in g 2 |
| Defer in g 1 |
| Defer in g 0 |
| Recovered in f 4 |
| Returned normally from f.</pre> |
| |
| <p> |
| If we remove the deferred function from f the panic is not recovered and |
| reaches the top of the goroutine's call stack, terminating the program. This |
| modified program will output: |
| </p> |
| |
| <pre>Calling g. |
| Printing in g 0 |
| Printing in g 1 |
| Printing in g 2 |
| Printing in g 3 |
| Panicking! |
| Defer in g 3 |
| Defer in g 2 |
| Defer in g 1 |
| Defer in g 0 |
| panic: 4 |
| |
| panic PC=0x2a9cd8 |
| [stack trace omitted]</pre> |
| |
| <p> |
| For a real-world example of <b>panic</b> and <b>recover</b>, see the |
| <a href="/pkg/encoding/json/">json package</a> from the Go standard library. |
| It decodes JSON-encoded data with a set of recursive functions. |
| When malformed JSON is encountered, the parser calls panic to unwind the |
| stack to the top-level function call, which recovers from the panic and returns |
| an appropriate error value (see the 'error' and 'unmarshal' methods of |
| the decodeState type in |
| <a href="/src/pkg/encoding/json/decode.go">decode.go</a>). |
| </p> |
| |
| <p> |
| The convention in the Go libraries is that even when a package uses panic |
| internally, its external API still presents explicit error return values. |
| </p> |
| |
| <p> |
| Other uses of <b>defer</b> (beyond the file.Close example given earlier) |
| include releasing a mutex: |
| </p> |
| |
| <pre>mu.Lock() |
| defer mu.Unlock()</pre> |
| |
| <p> |
| printing a footer: |
| </p> |
| |
| <pre>printHeader() |
| defer printFooter()</pre> |
| |
| <p> |
| and more. |
| </p> |
| |
| <p> |
| In summary, the defer statement (with or without panic and recover) provides an |
| unusual and powerful mechanism for control flow. It can be used to model a |
| number of features implemented by special-purpose structures in other |
| programming languages. Try it out. |
| </p> |