Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go: returning from defer

I want to return an error from a function if it panics (in Go):

func getReport(filename string) (rep report, err error) {     rep.data = make(map[string]float64)      defer func() {         if r := recover(); r != nil {             fmt.Println("Recovered in f", r)             err, _ = r.(error)             return nil, err         }     }()     panic("Report format not recognized.")     // rest of the getReport function, which can try to out-of-bound-access a slice     ... }  

I appear to have misunderstood the very concept of panic and defer. Can anybody enlighten me?

like image 607
jrichner Avatar asked Nov 12 '13 16:11

jrichner


People also ask

Can you return from a defer Golang?

In a deferred function you can alter the returned parameters, but you can't return a new set.

What does defer mean in Go?

A defer statement defers the execution of a function until the surrounding function returns. The deferred call's arguments are evaluated immediately, but the function call is not executed until the surrounding function returns. < 12/14 >

Is defer called before return?

Like the Defer Completion example, a defer statement can be used ensure a completion block is called with appropriate values before a function returns. Defer Logic. Like the Defer Logic example, a defer statement can be used to ensure key logic like closing a file executes before a function returns.

Why do we use defer?

Defer is used to ensure that a function call is performed later in a program's execution, usually for purposes of cleanup. defer is often used where e.g. ensure and finally would be used in other languages.


1 Answers

In a deferred function you can alter the returned parameters, but you can't return a new set. So a simple change to what you have will make it work.

There is another problem with what you wrote, namely that the you've paniced with a string but are expecting an error in your type assertion.

Here is a fix for both of those (Play)

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:             err = errors.New("Unknown panic")         }         // invalidate rep         rep = nil         // return the modified err and rep     } }() 
like image 119
Nick Craig-Wood Avatar answered Sep 23 '22 18:09

Nick Craig-Wood