这个Go闭包的例子是如何工作的?

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

How does this example of a Go closure work?

问题

我正在阅读一本(非常好的)Go 书籍,看到了这个例子,但我不明白它是如何工作的。

func makeEvenGenerator() func() uint {
    i := uint(0)
    return func() (ret uint) {
        ret = i
        i += 2
        return
    }
}
func main() {
    nextEven := makeEvenGenerator()
    fmt.Println(nextEven()) // 0
    fmt.Println(nextEven()) // 2
    fmt.Println(nextEven()) // 4
}

递增 i 是闭包的常见行为,这没问题。但是如果你看看 nextEven,它是一个不带参数并返回一个名为 retuint 的函数。但给返回值命名有什么意义呢?难道不是调用这个函数的代码使用自己的变量名吗?

而且返回语句没有返回任何东西,那么打印的是什么呢?这个函数是如何输出 0 / 2 / 4 的?

这与下面的代码有什么不同呢?

func makeEvenGenerator() func() uint {
    i := uint(0)
    return func() uint {
        current := i
        i += 2
        return current
    }
}

后者似乎更简单,更明显。我是否错过了一些深层的 Go / 数学概念?

英文:

I'm reading a (really good) Go book and saw this example, but I don't see how it works.

func makeEvenGenerator() func() uint {
    i := uint(0)
    return func() (ret uint) {
        ret = i
        i += 2
        return
    }
}
func main() {
    nextEven := makeEvenGenerator()
    fmt.Println(nextEven()) // 0
    fmt.Println(nextEven()) // 2
    fmt.Println(nextEven()) // 4
}

Incrementing i is common closure behaviour. That's fine. But if you look at nextEven, it's a function that takes no arguments and returns a uint called ret. But what's the point of naming the return value? Won't any code that calls this use its own variable name?

And the return statement returns nothing - so what's being printed? How is 0 / 2 / 4 coming out of this function?

And how is this different from doing this:

func makeEvenGenerator() func() uint {
	i := uint(0)
	return func() uint {
		current := i
		i += 2
		return current
	}
}

Which seems much simpler and makes things more obvious. Is there some deep Go / math concept that I'm missing?

答案1

得分: 12

返回语句返回的“nothing”是返回了命名的结果参数ret。命名的结果参数(http://golang.org/doc/effective_go.html#named-results)是一种语法糖,它在函数中引入了局部变量,如果有一个裸返回,这些变量将被返回。

在这种特定情况下,使用命名结果参数没有任何好处,可能会比有帮助的地方更加混淆。

通常有两种情况下可以使用命名结果参数:想要从defer中更改返回值时,以及为了记录它们的使用,通常可以看到返回两个或更多值的函数,例如Read(b []byte) (n int, err error)

英文:

The return statement that is returning "nothing" is returning the named result parameter ret. Named result parameters (http://golang.org/doc/effective_go.html#named-results) are syntactic sugar that introduce local variables in the function that will be returned if there's a bare return.

In this specific case, there's no benefit to using one and it probably does confuse more than it helps.

Usually there are two cases where named result parameters are of use: When wanting to change return values from a defer, and for the sake of documenting their use, as can often be seen with functions that return two or more values, such as Read(b []byte) (n int, err error)

huangapple
  • 本文由 发表于 2013年8月14日 01:47:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/18215845.html
匿名

发表评论

匿名网友

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

确定