Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gometalinter / errcheck returns a warning on deferring a func which returns a variable

gometalinter and errcheck return me a warning about deferring a function which returns a variable.

Example in a web request:

defer r.Body.Close()

In this case, Close returns an error variable and it's not checked.

Is the best method / idiomatic to defer it inside another function?

defer func() {
    err := r.Body.Close()
    if err != nil {
        // fmt, panic or whatever
    }
}()
like image 785
Andrea Sessa Avatar asked Nov 03 '16 09:11

Andrea Sessa


1 Answers

If a deferred function has any return values, they are discarded when the function completes (for more details check Spec: Defer statements).

So the only way to check the return value is to store it, and it is only possible if not the function itself is deferred, but another function that calls it.

One way to do it is using an anonymous function as you did, which may be slightly simplified:

defer func() {
    if err := r.Body.Close(); err != nil {
        fmt.Println("Error when closing:", err)
    }
}()

Or you may create a helper function for it:

func Check(f func() error) {
    if err := f(); err != nil {
        fmt.Println("Received error:", err)
    }
}

And using it:

defer Check(r.Body.Close)

The helper function of course can be used multiple times, e.g.:

defer Check(r.Body.Close)
defer Check(SomeOtherFunc)

For which you may also create a modified helper function, which may accept multiple functions:

func Checks(fs ...func() error) {
    for i := len(fs) - 1; i >= 0; i-- {
        if err := fs[i](); err != nil {
            fmt.Println("Received error:", err)
        }
    }
}

And using it:

defer Checks(r.Body.Close, SomeOtherFunc)

Note that I intentionally used a downward loop in Checks() to mimic the first-in-last-out nature of the execution of deferred functions, because the last defer will be executed first, and so using a downward loop the last function value passed to Checks() will be executed first.

like image 136
icza Avatar answered Nov 16 '22 00:11

icza