github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/blog/content/defer-panic-and-recover.article (about) 1 Defer, Panic, and Recover 2 4 Aug 2010 3 Tags: defer, panic, recover, technical, function 4 5 Andrew Gerrand 6 7 * Introduction 8 9 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. 10 11 12 A *defer*statement* 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. 13 14 15 For example, let's look at a function that opens two files and copies the contents of one file to the other: 16 17 18 func CopyFile(dstName, srcName string) (written int64, err error) { 19 src, err := os.Open(srcName) 20 if err != nil { 21 return 22 } 23 24 dst, err := os.Create(dstName) 25 if err != nil { 26 return 27 } 28 29 written, err = io.Copy(dst, src) 30 dst.Close() 31 src.Close() 32 return 33 } 34 35 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: 36 37 38 func CopyFile(dstName, srcName string) (written int64, err error) { 39 src, err := os.Open(srcName) 40 if err != nil { 41 return 42 } 43 defer src.Close() 44 45 dst, err := os.Create(dstName) 46 if err != nil { 47 return 48 } 49 defer dst.Close() 50 51 return io.Copy(dst, src) 52 } 53 54 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 _will_ be closed. 55 56 The behavior of defer statements is straightforward and predictable. There are three simple rules: 57 58 1. _A_deferred_function's_arguments_are_evaluated_when_the_defer_statement_is_evaluated._ 59 60 In this example, the expression "i" is evaluated when the Println call is deferred. The deferred call will print "0" after the function returns. 61 62 63 func a() { 64 i := 0 65 defer fmt.Println(i) 66 i++ 67 return 68 } 69 70 2. _Deferred_function_calls_are_executed_in_Last_In_First_Out_order_after_the_surrounding_function_returns._ 71 72 This function prints "3210": 73 74 func b() { 75 for i := 0; i < 4; i++ { 76 defer fmt.Print(i) 77 } 78 } 79 80 81 3. _Deferred_functions_may_read_and_assign_to_the_returning_function's_named_return_values._ 82 83 In this example, a deferred function increments the return value i _after_ the surrounding function returns. Thus, this function returns 2: 84 85 func c() (i int) { 86 defer func() { i++ }() 87 return 1 88 } 89 90 91 This is convenient for modifying the error return value of a function; we will see an example of this shortly. 92 93 94 *Panic* is a built-in function that stops the ordinary flow of control and begins _panicking_. 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. 95 96 97 *Recover* 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. 98 99 100 Here's an example program that demonstrates the mechanics of panic and defer: 101 102 package main 103 104 import "fmt" 105 106 func main() { 107 f() 108 fmt.Println("Returned normally from f.") 109 } 110 111 func f() { 112 defer func() { 113 if r := recover(); r != nil { 114 fmt.Println("Recovered in f", r) 115 } 116 }() 117 fmt.Println("Calling g.") 118 g(0) 119 fmt.Println("Returned normally from g.") 120 } 121 122 func g(i int) { 123 if i > 3 { 124 fmt.Println("Panicking!") 125 panic(fmt.Sprintf("%v", i)) 126 } 127 defer fmt.Println("Defer in g", i) 128 fmt.Println("Printing in g", i) 129 g(i + 1) 130 } 131 132 133 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. 134 135 136 The program will output: 137 138 139 Calling g. 140 Printing in g 0 141 Printing in g 1 142 Printing in g 2 143 Printing in g 3 144 Panicking! 145 Defer in g 3 146 Defer in g 2 147 Defer in g 1 148 Defer in g 0 149 Recovered in f 4 150 Returned normally from f. 151 152 153 154 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: 155 156 157 Calling g. 158 Printing in g 0 159 Printing in g 1 160 Printing in g 2 161 Printing in g 3 162 Panicking! 163 Defer in g 3 164 Defer in g 2 165 Defer in g 1 166 Defer in g 0 167 panic: 4 168 169 panic PC=0x2a9cd8 170 [stack trace omitted] 171 172 173 174 For a real-world example of *panic* and *recover*, see the [[http://golang.org/pkg/encoding/json/][json package]] 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 [[http://golang.org/src/pkg/encoding/json/decode.go][decode.go]]). 175 176 The convention in the Go libraries is that even when a package uses panic internally, its external API still presents explicit error return values. 177 178 179 Other uses of *defer* (beyond the file.Close example given earlier) include releasing a mutex: 180 181 mu.Lock() 182 defer mu.Unlock() 183 184 185 186 printing a footer: 187 188 189 printHeader() 190 defer printFooter() 191 192 193 194 and more. 195 196 197 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.