diff options
Diffstat (limited to 'doc/articles/defer_panic_recover.html')
-rw-r--r-- | doc/articles/defer_panic_recover.html | 197 |
1 files changed, 0 insertions, 197 deletions
diff --git a/doc/articles/defer_panic_recover.html b/doc/articles/defer_panic_recover.html deleted file mode 100644 index c964cd368..000000000 --- a/doc/articles/defer_panic_recover.html +++ /dev/null @@ -1,197 +0,0 @@ -<!--{ - "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> |