Reputation: 11976
I'm trying to understand how to recover from panic situation. Normally, something like this will do:
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
I can understand those much. But I've seen code snippet like the following:
if r, ok := recover().(error); ok {
fmt.Println("Recovered in f", r)
}
What's the .(error)
part doing?
Upvotes: 15
Views: 21967
Reputation: 1327064
It is a type assertion which check if the error recovered is of a certain type.
It that type assertion fails, that causes a run-time error that continues the stack unwinding as though nothing had interrupted it.
This is useful when you define a local MyError
type for error, and you want to recover only from that type.
You can see an example in "Error handling and Go"
Client code can test for a net.Error with a type assertion and then distinguish transient network errors from permanent ones.
For instance, a web crawler might:
- sleep and retry when it encounters a temporary error
- and give up otherwise.
if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
time.Sleep(1e9)
continue
}
if err != nil {
log.Fatal(err)
}
If you have several types of error you want to recover, you can use a type switch is in "Golang: returning from defer"
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
// find out exactly what the error was and set err
switch x := r.(type) {
case string:
err = errors.New(x)
case error:
err = x
default:
// Fallback err (per specs, error strings should be lowercase w/o punctuation
err = errors.New("unknown panic")
}
// invalidate rep
rep = nil
// return the modified err and rep
}
}()
Upvotes: 32