When to use os.Exit() and panic()?
Could someone explain the key differences between os.Exit()
and panic()
and how they are used in practice in Go?
Solution 1:
First of all, whenever you have a "how it is used in practice" question, a good way to start is to search the Go source code (or any big enough Go code base, really), and the package docs for answers.
Now, os.Exit
and panic
are quite different. panic
is used when the program, or its part, has reached an unrecoverable state.
When
panic
is called, including implicitly for run-time errors such as indexing a slice out of bounds or failing a type assertion, it immediately stops execution of the current function and begins unwinding the stack of the goroutine, running any deferred functions along the way. If that unwinding reaches the top of the goroutine's stack, the program dies.
os.Exit
is used when you need to abort the program immediately, with no possibility of recovery or running a deferred clean-up statement, and also return an error code (that other programs can use to report what happened). This is useful in tests, when you already know that after this one test fails, the other will fail as well, so you might as well just exit now. This can also be used when your program has done everything it needed to do, and now just needs to exit, i.e. after printing a help message.
Most of the time you won't use panic
(you should return an error
instead), and you almost never need os.Exit
outside of some cases in tests and for quick program termination.
Solution 2:
First of all, os.Exit()
can be used to exit the program normally without an error, and panic not, so that's one key distinction. Another is that panic somewhere can be caught and ignored or logged using recover
.
But if we're talking about an erroneous exit code, let's say:
Use panic
when something goes horribly wrong, probably a programmer error that should have been caught before going to production. This is why it prints the stack.
Use os.Exit(errorCode)
or something like that if you want to:
control the exit code of the program for scripting purposes.
want an orderly exit on an error that is expected (e.g user input error).
So basically panic is for you, a bad exit code is for your user.
Solution 3:
The key differences are:
-
os.Exit
skips the execution of deferred function. - With
os.Exit
, you can specify the exit code. -
panic
is terminating whileos.Exit
is not. (Seems other answers do not mention this.)
If you need to execute the deferred function, you have no choice but panic
. (On the other hand, if you want to skip execution of deferred function, use os.Exit
.)
If a non-void function is defined in such a way:
- the function contains a lot of branches
- all branches are terminated with
return
orpanic
Then you cannot replace panic
with os.Exit
otherwise the compiler will refuse to compile the program, saying "missing return at end of function". (Go is very dumb here, even log.Panic
does not terminate a function.)
Under other conditions:
- Use
panic
when something really wired happens, e.g. programming logic error. - Use
os.Exit
when you want an immediate exit, with specified exit code.