1
0
mirror of https://github.com/golang/go synced 2024-11-25 04:57:56 -07:00

Effective Go: add a section on defer.

R=rsc, iant
CC=golang-dev
https://golang.org/cl/1694044
This commit is contained in:
Rob Pike 2010-06-16 13:47:36 -07:00
parent 743f818218
commit 050905b985

View File

@ -770,6 +770,139 @@ func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
} }
</pre> </pre>
<h3 id="defer">Defer</h3>
<p>
Go's <code>defer</code> statement schedules a function call (the
<i>deferred</i> function) to be run immediately before the function
executing the <code>defer</code> returns. It's an unusual but
effective way to deal with situations such as resources that must be
released regardless of which path a function takes to return. The
canonical examples are unlocking a mutex or closing a file.
</p>
<pre>
// Contents returns the file's contents as a string.
func Contents(filename string) (string, os.Error) {
f, err := os.Open(filename, os.O_RDONLY, 0)
if err != nil {
return "", err
}
defer f.Close() // f.Close will run when we're finished.
var result []byte
buf := make([]byte, 100)
for {
n, err := f.Read(buf[0:])
result = bytes.Add(result, buf[0:n])
if err != nil {
if err == os.EOF {
break
}
return "", err // f will be closed if we return here.
}
}
return string(result), nil // f will be closed if we return here.
}
</pre>
<p>
Deferring a function like this has two advantages. First, it
guarantees that you will never forget to close the file, a mistake
that's easy to make if you later edit the function to add a new return
path. Second, it means that the close sits near the open,
which is much clearer than placing it at the end of the function.
</p>
<p>
The arguments to the deferred function (which includes the receiver if
the function is a method) are evaluated when the <i>defer</i>
executes, not when the <i>call</i> executes. Besides avoiding worries
about variables changing values as the function executes, this means
that a single deferred call site can defer multiple function
executions. Here's a silly example.
</p>
<pre>
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
</pre>
<p>
Deferred functions are executed in LIFO order, so this code will cause
<code>4 3 2 1 0</code> to be printed when the function returns. A
more plausible example is a simple way to trace function execution
through the program. We could write a couple of simple tracing
routines like this:
</p>
<pre>
func trace(s string) { fmt.Println("entering:", s) }
func untrace(s string) { fmt.Println("leaving:", s) }
// Use them like this:
func a() {
trace("a")
defer untrace("a")
// do something....
}
</pre>
<p>
We can do better by exploiting the fact that arguments to deferred
functions are evaluated when the <code>defer</code> executes. The
tracing routine can set up the argument to the untracing routine.
This example:
</p>
<pre>
func trace(s string) string {
fmt.Println("entering:", s)
return s
}
func un(s string) {
fmt.Println("leaving:", s)
}
func a() {
defer un(trace("a"))
fmt.Println("in a")
}
func b() {
defer un(trace("b"))
fmt.Println("in b")
a()
}
func main() {
b()
}
</pre>
<p>
prints
</p>
<pre>
entering: b
in b
entering: a
in a
leaving: a
leaving: b
</pre>
<p>
For programmers accustomed to block-level resource management from
other languages, <code>defer</code> may seem peculiar, but its most
interesting and powerful applications come precisely from the fact
that it's not block-based but function based. In the section on
<code>panic</code> and <code>recover</code> we'll see an example.
</p>
<h2 id="data">Data</h2> <h2 id="data">Data</h2>
<h3 id="allocation_new">Allocation with <code>new()</code></h3> <h3 id="allocation_new">Allocation with <code>new()</code></h3>
@ -2436,6 +2569,13 @@ for try := 0; try &lt; 2; try++ {
} }
</pre> </pre>
<h3 id="panic_recover">Panic and recover</h3>
<p>
TODO: Short discussion of panic and recover goes here.
</p>
<h2 id="web_server">A web server</h2> <h2 id="web_server">A web server</h2>
<p> <p>