diff --git a/doc/effective_go.html b/doc/effective_go.html index 18a3e981a9..78eadbd7ba 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -770,6 +770,139 @@ func ReadFull(r Reader, buf []byte) (n int, err os.Error) { } +

Defer

+ +

+Go's defer statement schedules a function call (the +deferred function) to be run immediately before the function +executing the defer 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. +

+ +
+// 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.
+}
+
+ +

+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. +

+ +

+The arguments to the deferred function (which includes the receiver if +the function is a method) are evaluated when the defer +executes, not when the call 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. +

+ +
+for i := 0; i < 5; i++ {
+    defer fmt.Printf("%d ", i)
+}
+
+ +

+Deferred functions are executed in LIFO order, so this code will cause +4 3 2 1 0 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: +

+ +
+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....
+}
+
+ +

+We can do better by exploiting the fact that arguments to deferred +functions are evaluated when the defer executes. The +tracing routine can set up the argument to the untracing routine. +This example: +

+ +
+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()
+}
+
+ +

+prints +

+ +
+entering: b
+in b
+entering: a
+in a
+leaving: a
+leaving: b
+
+ +

+For programmers accustomed to block-level resource management from +other languages, defer 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 +panic and recover we'll see an example. +

+

Data

Allocation with new()

@@ -1341,9 +1474,9 @@ for a min function that chooses the least of a list of integers: func Min(a ...int) int { min := int(^uint(0) >> 1) // largest int for _, i := range a { - if i < min { - min = i - } + if i < min { + min = i + } } return min } @@ -2436,6 +2569,13 @@ for try := 0; try < 2; try++ { } +

Panic and recover

+ +

+TODO: Short discussion of panic and recover goes here. +

+ +

A web server