Use cases for panic
suggest changeUsing of panic
in Go should be extremely rare but it does have valid use cases.
Force crash on bad API usage
This is similar to using assert
in other languages.
Imagine you're writing a httpGet
function that downloads content of the URL.
What should happen when URL is empty string? It's obviously a mistake on the part of the caller.
You can return an error but you can also for a crash with panic
:
func httpGet(uri string) ([]byte, error) {
if uri == "" {
panic("uri cannot be empty")
}
// ... download the url
}
Sometimes it's better because an error can be ignored or the program might assume that it's a valid error condition, like a website being down.
Forcing a crash increases chances that the developer will look at the problem and fix it.
If you do it often, this helper function will be useful:
func panicIf(cond bool, args ...interface{}) {
if !cond {
return
}
if len(args) == 0 {
panic(errors.New("cond failed"))
}
format := args[0].(string)
args = args[1:]
err := fmt.Errorf(format, args)
panic(err)
}
Now this can be written as a single line:
func httpGet(uri string) ([]byte, error) {
panicIf(uri == "", "uri cannot be empty")
// ... download the url
}
Function panicIf
is flexible. You can call it as:
panicIf(n < 0)
and it'll panic with generic error messagepanicIf(n < 0, "n must be >= 0")
to provide more descriptive messagepanicIf(n < 0, "n is %d and must be >= 0", n)
to provide even more descriptive message
Simplifying flow control in isolated piece of code
Sometimes it’s easier to propagate an error by panicking and recovering rather than returning errors.
This might be true e.g. in a parser.
When you use that technique, you should observe one rule: panic
should not cross public API boundary.
In other words, if you implement a parser library, you should always recover
all panic
s your code creates. Panic used for easier flow control should never reach the caller of your package API.
Protect a program from a crash in a goroutine
Unhandled panic
in a goroutine crashes a program.
This is the right behavior most of the time (panic
indicates a serious bug and you should fix bugs, not cover them up).
In rare occasions we don't want a single goroutine to bring down the whole program so we can wrap the code with a function that does recover
at the top.
This technique is used in Go’s http server package which handles each connection in a separate goroutine. In a web server we don't want a rare bug in request handling code to crash the program.