Empty return in func with return value in golang

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

Empty return in func with return value in golang

问题

我正在阅读在Github上用**Golang**编写的一些代码,并发现了一段非常有趣的代码。我简化了它以便清楚。

func Insert(docs ...interface{}) (err error) {
    for i := 0; i < 3; i++ {
        err = fmt.Errorf("")
        if err.Error() != "EOF" {
            return
        }
    }
    return
}

我对这里的空返回值感到非常困惑...它是如何工作的?他返回nil作为错误还是跳出循环?我知道这个问题看起来很愚蠢,但我在Go文档中找不到任何相关信息...另外,我不明白我们如何返回已经在func中声明的err变量。(err error)是否意味着我们已经在func中有一个可用的错误变量,如果没有指定,则作为默认返回值使用?那么为什么我们在func的末尾隐式地返回err呢?

如果能解释一下,我将非常感激。

英文:

I was reading some code written in Golang on Github and found a very interesting piece of code. I simplified it to be clear.

func  Insert(docs ...interface{}) (err error) {
	for i := 0; i &lt; 3; i++ {
		err = fmt.Errorf(&quot;&quot;)
		if err.Error()!=&quot;EOF&quot; {
			return
		}
	}
	return 
}

I'm very confused about empty return here... How it works? Does he return nil as error or breaks for loop? I understand that this question looks dummy, but I cannot find any info on this in go docs... Also, I don't understand how we can return err, which is, as I understood, declared somehow in return. Does (err error) means that we already have an error variable available in our func which is used as default return value if none specified? Why then we implicitly make return err at the end of func?

I'll be very gratefull for explanation.

答案1

得分: 51

该函数使用了“命名”的返回值。

根据规范中的返回语句:

如果函数的结果类型指定了结果参数的名称,那么表达式列表可以为空。结果参数的作用类似于普通的局部变量,函数可以根据需要为它们赋值。"return"语句返回这些变量的值。

无论如何声明,所有的结果值在进入函数时都会被初始化为其类型的零值。在执行任何延迟函数之前,"return"语句会设置结果参数的值。

使用命名返回可以节省手动分配局部变量的代码,并且有时可以简化混乱的if/else语句或长列表的返回值。

func a() (x []string, err error) {
    return
}

实际上只是下面代码的简写形式:

func a() ([]string, error) {
    var x []string
    var err error
    return x, err
}

它更加简短,我同意它可能不太明显。

命名返回有时是必需的,因为它允许在延迟函数中访问它们,但据我所知,裸返回只是一种语法糖,从严格意义上讲,它从来都不是必需的。

我经常在具有多个返回值的函数中的错误返回情况下看到它的使用。

if err != nil {
    return
}
return a, b, c, nil

比起下面的写法更简单:

if err != nil {
    return nil, nil, nil, err
}
return a, b, c, nil

当你需要多次编写它时,这样做更容易。而且,如果你改变函数签名以添加额外的“真实”返回值,你不需要修改这些返回语句。

在我搜索的代码库中,我发现它们通常用于隐藏其他问题,比如过于复杂的多用途函数、过深的if/else嵌套等等。

英文:

The function uses a "named" return value.

From the spec on return statements:

> The expression list may be empty if the function's result type
> specifies names for its result parameters. The result parameters act
> as ordinary local variables and the function may assign values to them
> as necessary. The "return" statement returns the values of these
> variables.
>
> Regardless of how they are declared, all the result values are
> initialized to the zero values for their type upon entry to the
> function. A "return" statement that specifies results sets the result
> parameters before any deferred functions are executed.

Using named returns allows you to save some code on manually allocating local variables, and can sometimes clean up messy if/else statements or long lists of return values.

func a()(x []string, err error){
    return
}

is really just shorthand for

func a() ([]string,error){
  var x []string
  var err error
  return x,err
}

Its a bit shorter, and I agree that it may be less obvious.

Named returns are sometimes needed, as it allows things like accessing them inside a deferred function, but the naked return is just syntactic sugar as far as I can tell, and is never strictly required.

One place I see it commonly is in error return cases in functions that have many return values.

if(err != nil){
   return
}
return a,b,c,nil

is easier than

if(err != nil){
   return nil,nil,nil,err
}
return a,b,c,nil

when you have to write it a bunch of times. And you don't have to modify those returns if you change the signature to have additional "real" return values.

Most places I am using them in the codebase I just searched, they definitely seem to be hiding other smells, like overly complex multi-purpose functions, too deep if/else nesting and stuff like that.

答案2

得分: 8

Go的返回值可以被命名。如果是这样,它们被视为在函数顶部定义的变量。

package main

import "fmt"

func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return
}

func main() {
    fmt.Println(split(17))
}

https://tour.golang.org/basics/7

英文:

Go's return values may be named. If so, they are treated as variables defined at the top of the function.

package main

import &quot;fmt&quot;

func split(sum int) (x, y int) {
    x = sum * 4 / 9
	y = sum - x
   return
}

func main() {
    fmt.Println(split(17))
}

https://tour.golang.org/basics/7

答案3

得分: 5

当你有一个命名的返回值(这里是err):

func Insert(docs ...interface{}) (err error) {

这将创建一个函数内部的变量,并且如果你只是调用return而没有参数,它会返回这个局部变量。所以在这个函数中,

return

与下面的代码是相同的,并且意味着:

return err

这在Go语言之旅规范中有详细说明。

英文:

When you have a named return value (err here):

func  Insert(docs ...interface{}) (err error) {

This creates a function-local variable by that name, and if you just call return with no parameters, it returns the local variable. So in this function,

return

Is the same as, and implies,

return err

This is detailed in the tour and in the spec.

huangapple
  • 本文由 发表于 2017年7月21日 21:49:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/45239409.html
匿名

发表评论

匿名网友

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

确定