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
}
}()
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.