mirror of
				https://github.com/golang/go.git
				synced 2025-11-04 02:30:57 +00:00 
			
		
		
		
	Delete () from function names and change the reference to some functions to the correct term, methods. R=golang-dev, dsymonds CC=golang-dev https://golang.org/cl/5874063
		
			
				
	
	
		
			197 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			197 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!--{
 | 
						|
	"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>
 |