gometalinter / errcheck在延迟执行返回变量的函数时会返回一个警告。

huangapple go评论79阅读模式
英文:

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

问题

gometalintererrcheck给我返回了一个关于延迟执行返回变量的函数的警告。

在一个网络请求的示例中:

defer r.Body.Close()

在这种情况下,Close函数返回一个错误变量,并且没有进行检查。

最佳的方法/惯用的做法是将其延迟执行在另一个函数中吗?

defer func() {
    err := r.Body.Close()
    if err != nil {
        // fmt、panic或其他处理方式
    }
}()
英文:

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

答案1

得分: 22

如果延迟函数有任何返回值,在函数完成时它们将被丢弃(更多细节请参阅规范:延迟语句)。

因此,检查返回值的唯一方法是将其存储起来,而且只有在不是函数本身被延迟,而是调用它的另一个函数时才可能。

一种方法是使用匿名函数,就像你所做的那样,可能稍微简化一下:

defer func() {
    if err := r.Body.Close(); err != nil {
        fmt.Println("关闭时发生错误:", err)
    }
}()

或者你可以为此创建一个辅助函数:

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

并使用它:

defer Check(r.Body.Close)

当然,辅助函数可以多次使用,例如:

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

对于这种情况,你还可以创建一个修改后的辅助函数,它可以接受多个函数:

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

并使用它:

defer Checks(r.Body.Close, SomeOtherFunc)

请注意,我有意在Checks()中使用了一个向下循环,以模拟延迟函数执行的“后进先出”的特性,因为最后一个defer将首先执行,所以使用向下循环,最后一个传递给Checks()的函数值将首先执行。

英文:

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.

huangapple
  • 本文由 发表于 2016年11月3日 17:22:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/40397781.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定