What does this print? (Rules of recover)
Question 306HardGo 1.22 to 1.25
func helper() {
if r := recover(); r != nil {
fmt.Println("recovered:", r)
}
}
func a() { defer helper(); panic("A") } // helper IS the deferred func
func b() { defer func() { helper() }(); panic("B") } // helper called BY deferred func
func c() { defer recover(); panic("C") } // recover deferred directly
func main() {
a()
fmt.Println("after a")
b()
fmt.Println("after b")
}
Output: recovered: A, after a, and then the program crashes with panic: B. recover stops a panic only when it is called directly by a deferred function while the goroutine is panicking. In a, helper is the deferred function, so it works. In b, helper is one call deeper, so recover returns nil and the panic continues. c fails too, because defer recover() makes recover itself the deferred call rather than a call made by a deferred function.
Other rules: outside a panic, recover returns nil. It works only in the same goroutine as the panic. After recovering, the function whose defer recovered returns normally to its caller (with named results set to whatever the defer assigned), and execution does not resume at the point of the panic.
More on Error Handling & panics
- Q304When should you wrap an error and when should you not? How do you handle errors at package boundaries?
- Q305When is it appropriate to
panicinstead of returning an error? - Q307A goroutine panics. Can a
recoverinmaincatch it? How do you protect background goroutines? - Q308What does this print? (Defer order during panic)
- Q309How do you convert a panic into an error returned from a function?
- Q310What happens with
panic(nil)and with re-panicking? How did Go 1.21 change this?