github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/doc/articles/defer_panic_recover.html (about)

     1  <!--{
     2  	"Title": "Defer, Panic, and Recover",
     3  	"Template": true
     4  }-->
     5  
     6  <p>
     7  Go has the usual mechanisms for control flow: if, for, switch, goto.  It also
     8  has the go statement to run code in a separate goroutine.  Here I'd like to
     9  discuss some of the less common ones: defer, panic, and recover.
    10  </p>
    11   
    12  <p>
    13  A <b>defer statement</b> pushes a function call onto a list. The list of saved
    14  calls is executed after the surrounding function returns. Defer is commonly
    15  used to simplify functions that perform various clean-up actions.
    16  </p>
    17   
    18  <p>
    19  For example, let's look at a function that opens two files and copies the
    20  contents of one file to the other:
    21  </p>
    22   
    23  {{code "/doc/progs/defer.go" `/func CopyFile/` `/STOP/`}}
    24  
    25  <p>
    26  This works, but there is a bug. If the call to os.Create fails, the
    27  function will return without closing the source file. This can be easily
    28  remedied by putting a call to src.Close before the second return statement,
    29  but if the function were more complex the problem might not be so easily
    30  noticed and resolved. By introducing defer statements we can ensure that the
    31  files are always closed:
    32  </p>
    33   
    34  {{code "/doc/progs/defer2.go" `/func CopyFile/` `/STOP/`}}
    35  
    36  <p>
    37  Defer statements allow us to think about closing each file right after opening
    38  it, guaranteeing that, regardless of the number of return statements in the
    39  function, the files <i>will</i> be closed.
    40  </p>
    41   
    42  <p>
    43  The behavior of defer statements is straightforward and predictable. There are
    44  three simple rules:
    45  </p>
    46   
    47  <p>
    48  1. <i>A deferred function's arguments are evaluated when the defer statement is
    49  evaluated.</i> 
    50  </p>
    51   
    52  <p>
    53  In this example, the expression "i" is evaluated when the Println call is
    54  deferred. The deferred call will print "0" after the function returns.
    55  </p>
    56   
    57  {{code "/doc/progs/defer.go" `/func a/` `/STOP/`}}
    58  
    59  <p>
    60  2. <i>Deferred function calls are executed in Last In First Out order
    61  </i>after<i> the surrounding function returns.</i> 
    62  </p>
    63   
    64  <p>
    65  This function prints "3210":
    66  </p>
    67  
    68  {{code "/doc/progs/defer.go" `/func b/` `/STOP/`}}
    69   
    70  <p>
    71  3. <i>Deferred functions may read and assign to the returning function's named
    72  return values.</i> 
    73  </p>
    74   
    75  <p>
    76  In this example, a deferred function increments the return value i <i>after</i>
    77  the surrounding function returns. Thus, this function returns 2:
    78  </p>
    79  
    80  {{code "/doc/progs/defer.go" `/func c/` `/STOP/`}}
    81   
    82  <p>
    83  This is convenient for modifying the error return value of a function; we will
    84  see an example of this shortly.
    85  </p>
    86   
    87  <p>
    88  <b>Panic</b> is a built-in function that stops the ordinary flow of control and
    89  begins <i>panicking</i>. When the function F calls panic, execution of F stops,
    90  any deferred functions in F are executed normally, and then F returns to its
    91  caller. To the caller, F then behaves like a call to panic. The process
    92  continues up the stack until all functions in the current goroutine have
    93  returned, at which point the program crashes. Panics can be initiated by
    94  invoking panic directly. They can also be caused by runtime errors, such as
    95  out-of-bounds array accesses.
    96  </p>
    97   
    98  <p>
    99  <b>Recover</b> is a built-in function that regains control of a panicking
   100  goroutine. Recover is only useful inside deferred functions. During normal
   101  execution, a call to recover will return nil and have no other effect. If the
   102  current goroutine is panicking, a call to recover will capture the value given
   103  to panic and resume normal execution.
   104  </p>
   105   
   106  <p>
   107  Here's an example program that demonstrates the mechanics of panic and defer:
   108  </p>
   109  
   110  {{code "/doc/progs/defer2.go" `/package main/` `/STOP/`}}
   111   
   112  <p>
   113  The function g takes the int i, and panics if i is greater than 3, or else it
   114  calls itself with the argument i+1. The function f defers a function that calls
   115  recover and prints the recovered value (if it is non-nil). Try to picture what
   116  the output of this program might be before reading on.
   117  </p>
   118   
   119  <p>
   120  The program will output:
   121  </p>
   122   
   123  <pre>Calling g.
   124  Printing in g 0
   125  Printing in g 1
   126  Printing in g 2
   127  Printing in g 3
   128  Panicking!
   129  Defer in g 3
   130  Defer in g 2
   131  Defer in g 1
   132  Defer in g 0
   133  Recovered in f 4
   134  Returned normally from f.</pre> 
   135  
   136  <p>
   137  If we remove the deferred function from f the panic is not recovered and
   138  reaches the top of the goroutine's call stack, terminating the program. This
   139  modified program will output:
   140  </p>
   141   
   142  <pre>Calling g.
   143  Printing in g 0
   144  Printing in g 1
   145  Printing in g 2
   146  Printing in g 3
   147  Panicking!
   148  Defer in g 3
   149  Defer in g 2
   150  Defer in g 1
   151  Defer in g 0
   152  panic: 4
   153   
   154  panic PC=0x2a9cd8
   155  [stack trace omitted]</pre> 
   156  
   157  <p>
   158  For a real-world example of <b>panic</b> and <b>recover</b>, see the
   159  <a href="/pkg/encoding/json/">json package</a> from the Go standard library.
   160  It decodes JSON-encoded data with a set of recursive functions.
   161  When malformed JSON is encountered, the parser calls panic to unwind the
   162  stack to the top-level function call, which recovers from the panic and returns
   163  an appropriate error value (see the 'error' and 'unmarshal' methods of
   164  the decodeState type in
   165  <a href="/src/pkg/encoding/json/decode.go">decode.go</a>).
   166  </p>
   167  
   168  <p>
   169  The convention in the Go libraries is that even when a package uses panic
   170  internally, its external API still presents explicit error return values.
   171  </p>
   172   
   173  <p>
   174  Other uses of <b>defer</b> (beyond the file.Close example given earlier)
   175  include releasing a mutex:
   176  </p>
   177  
   178  <pre>mu.Lock()
   179  defer mu.Unlock()</pre> 
   180  
   181  <p>
   182  printing a footer:
   183  </p>
   184   
   185  <pre>printHeader()
   186  defer printFooter()</pre> 
   187  
   188  <p>
   189  and more.
   190  </p>
   191   
   192  <p>
   193  In summary, the defer statement (with or without panic and recover) provides an
   194  unusual and powerful mechanism for control flow.  It can be used to model a
   195  number of features implemented by special-purpose structures in other
   196  programming languages. Try it out.
   197  </p>