lang2
lang2

Reputation: 11976

golang recover return value syntax

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

Answers (1)

VonC
VonC

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

Related Questions