Skip to content

Commit 99b23a1

Browse files
committed
Effective Go: panic and recover
R=rsc, iant CC=golang-dev https://golang.org/cl/1718042
1 parent 050905b commit 99b23a1

File tree

1 file changed

+168
-3
lines changed

1 file changed

+168
-3
lines changed

doc/effective_go.html

+168-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ <h2 id="introduction">Introduction</h2>
2929
should read first.
3030
</p>
3131

32-
<h3 id="read">Examples</h3>
32+
<h3 id="examples">Examples</h3>
3333

3434
<p>
3535
The <a href="/src/pkg/">Go package sources</a>
@@ -2569,10 +2569,175 @@ <h2 id="errors">Errors</h2>
25692569
}
25702570
</pre>
25712571

2572-
<h3 id="panic_recover">Panic and recover</h3>
2572+
<h3 id="panic">Panic</h3>
25732573

25742574
<p>
2575-
TODO: Short discussion of panic and recover goes here.
2575+
The usual way to report an error to a caller is to return an
2576+
<code>os.Error</code> as an extra return value. The canonical
2577+
<code>Read</code> method is a well-known instance; it returns a byte
2578+
count and an <code>os.Error</code>. But what if the error is
2579+
unrecoverable? Sometimes the program simply cannot continue.
2580+
</p>
2581+
2582+
<p>
2583+
For this purpose, there is a built-in function <code>panic</code>
2584+
that in effect creates a run-time error that will stop the program
2585+
(but see the next section). The function takes a single argument
2586+
of arbitrary type&mdash;often a string&mdash;to be printed as the
2587+
program dies. It's also a way to indicate that something impossible has
2588+
happened, such as exiting an infinite loop. In fact, the compiler
2589+
recognizes a <code>panic</code> at the end of a function and
2590+
suppresses the usual check for a <code>return</code> statement.
2591+
</p>
2592+
2593+
2594+
<pre>
2595+
// A toy implementation of cube root using Newton's method.
2596+
func CubeRoot(x float64) float64 {
2597+
z := x/3 // Arbitrary intitial value
2598+
for i := 0; i < 1e6; i++ {
2599+
prevz := z
2600+
z -= (z*z*z-x) / (3*z*z)
2601+
if veryClose(z, prevz) {
2602+
return z
2603+
}
2604+
}
2605+
// A million iterations has not converged; something is wrong.
2606+
panic(fmt.Sprintf("CubeRoot(%g) did not converge", x)
2607+
}
2608+
</pre>
2609+
2610+
<p>
2611+
This is only an example but real library functions should
2612+
avoid <code>panic</code>. If the problem can be masked or worked
2613+
around, it's always better to let things continue to run rather
2614+
than taking down the whole program. One possible counterexample
2615+
is during initialization: if the library truly cannot set itself up,
2616+
it might be reasonable to panic, so to speak.
2617+
</p>
2618+
2619+
<pre>
2620+
var user = os.Getenv("USER")
2621+
2622+
func init() {
2623+
if user == "" {
2624+
panic("no value for $USER")
2625+
}
2626+
}
2627+
</pre>
2628+
2629+
<h3 id="recover">Recover</h3>
2630+
2631+
<p>
2632+
When <code>panic</code> is called, including implicitly for run-time
2633+
errors such indexing an array out of bounds or failing a type
2634+
assertion, it immediately stops execution of the current function
2635+
and begins unwinding the stack of the goroutine, running any deferred
2636+
functions along the way. If that unwinding reaches the top of the
2637+
goroutine's stack, the program dies. However, it is possible to
2638+
use the built-in function <code>recover</code> to regain control
2639+
of the goroutine and resume normal execution.
2640+
</p>
2641+
2642+
<p>
2643+
A call to <code>recover</code> stops the unwinding and returns the
2644+
argument passed to <code>panic</code>. Because the only code that
2645+
runs while unwinding is inside deferred functions, <code>recover</code>
2646+
is only useful inside deferred functions.
2647+
</p>
2648+
2649+
<p>
2650+
One application of <code>recover</code> is to shut down a failing goroutine
2651+
inside a server without killing the other executing goroutines.
2652+
</p>
2653+
2654+
<pre>
2655+
func server(workChan <-chan *Work) {
2656+
for work := range workChan {
2657+
safelyDo(work)
2658+
}
2659+
}
2660+
2661+
func safelyDo(work *Work) {
2662+
defer func() {
2663+
if err := recover(); err != nil {
2664+
log.Stderr("work failed:", err)
2665+
}
2666+
}()
2667+
do(work)
2668+
}
2669+
</pre>
2670+
2671+
<p>
2672+
In this example, if <code>do(work)</code> panics, the result will be
2673+
logged and the goroutine will exit cleanly without disturbing the
2674+
others. There's no need to do anything else in the deferred closure;
2675+
calling <code>recover</code> handles the condition completely.
2676+
</p>
2677+
2678+
<p>
2679+
Note that with this recovery pattern in place, the <code>do</code>
2680+
function (and anything it calls) can get out of any bad situation
2681+
cleanly by calling <code>panic</code>. We can use that idea to
2682+
simplify error handling in complex software. Let's look at an
2683+
idealized excerpt from the <code>regexp</code> package, which reports
2684+
parsing errors by calling <code>panic</code> with a local
2685+
<code>Error</code> type. Here's the definition of <code>Error</code>,
2686+
an <code>error</code> method, and the <code>Compile</code> function.
2687+
</p>
2688+
2689+
<pre>
2690+
// Error is the type of a parse error; it satisfies os.Error.
2691+
type Error string
2692+
func (e Error) String() string {
2693+
return string(e)
2694+
}
2695+
2696+
// error is a method of *Regexp that reports parsing errors by
2697+
// panicking with an Error.
2698+
func (regexp *Regexp) error(err string) {
2699+
panic(Error(err))
2700+
}
2701+
2702+
// Compile returns a parsed representation of the regular expression.
2703+
func Compile(str string) (regexp *Regexp, err os.Error) {
2704+
regexp = new(Regexp)
2705+
// doParse will panic if there is a parse error.
2706+
defer func() {
2707+
if e := recover(); e != nil {
2708+
regexp = nil // Clear return value.
2709+
err = e.(Error) // Will re-panic if not a parse error.
2710+
}
2711+
}()
2712+
return regexp.doParse(str), nil
2713+
}
2714+
</pre>
2715+
2716+
<p>
2717+
If <code>doParse</code> panics, the recovery block will set the
2718+
return value to <code>nil</code>&mdash;deferred functions can modify
2719+
named return values. It then will then check, in the assignment
2720+
to <code>err</code>, that the problem was a parse error by asserting
2721+
that it has type <code>Error</code>.
2722+
If it does not, the type assertion will fail, causing a run-time error
2723+
that continues the stack unwinding as though nothing had interrupted
2724+
it. This check means that if something unexpected happens, such
2725+
as an array index out of bounds, the code will fail even though we
2726+
are using <code>panic</code> and <code>recover</code> to handle
2727+
user-triggered errors.
2728+
</p>
2729+
2730+
<p>
2731+
With this error handling in place, the <code>error</code> method
2732+
makes it easy to report parse errors without worrying about unwinding
2733+
the parse stack by hand.
2734+
</p>
2735+
2736+
<p>
2737+
Useful though this pattern is, it should be used only within a package.
2738+
<code>Parse</code> turns its internal <code>panic</code> calls into
2739+
<code>os.Error</code> values; it does not expose <code>panics</code>
2740+
to its client. That is a good rule to follow.
25762741
</p>
25772742

25782743

0 commit comments

Comments
 (0)