Handling panics
…
The return value of
recoverisnilwhen the goroutine is not panicking or recover was not called directly by a deferred function. Conversely, if a goroutine is panicking andrecoverwas called directly by a deferred function, the return value ofrecoveris guaranteed not to benil. To ensure this, callingpanicwith anilinterface value (or an untypednil) causes a run-time panic.
As we saw before, you can pass any value, of an type, to the panic function. Then, if that panic is recovered, that value is returned by the call to recover:
func panicAndRecover() {
defer func() {
r := recover()
fmt.Printf("recovered value %v of type %T\n", r, r)
}()
panic(123)
}
Running this code will produce the following output:
recovered value 123 of type int
While you can panic with any value or type, it’s most common to panic with either a string, or an error.
The one special case, as mentioned, is the value nil, either an untyped literal nil, or a nil interface. The exception does not apply to nil maps, channels, or slices. If you panic with nil or a nil interface, it will… get this… cause a run-time panic. LOL.
You can distinguish such a panic from the type that it produces. If we modify the above code:
func panicAndRecover() {
defer func() {
r := recover()
fmt.Printf("recovered value %v of type %T\n", r, r)
}()
panic(nil)
}
We can see that the paniced value is of type *runtime.PanicNilError:
recovered value panic called with nil argument of type *runtime.PanicNilError
The
protectfunction in the example below invokes the function argumentgand protects callers from run-time panics raised byg.func protect(g func()) { defer func() { log.Println("done") // Println executes normally even if there is a panic if x := recover(); x != nil { log.Printf("run time panic: %v", x) } }() log.Println("start") g() }
Quotes from The Go Programming Language Specification Language version go1.23 (June 13, 2024)