Defer, return and Argument evaluation in golang

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

Defer, return and Argument evaluation in golang

问题

package main

import "fmt"

// fibonacci 是一个返回一个返回 int 的函数的函数。
func fibonacci() func() int {
	a, b := 0, 1
	return func() int {
		defer func() { a, b = b, a+b }()
		return a
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}

有人能解释一下为什么输出从 0, 1, 1, 2, 3, 5 ... 开始,而不是 1, 1, 2, 3, 5, ...?

据我理解,defer 语句会在 return 语句之前执行,这意味着 a、b 已经更新为 1, 1,并且应该返回 1。也许这与表达式何时求值或绑定有关,也许返回语句已经将 a 绑定为 0,然后在返回之前检查是否有 defer 语句?

如果有关于 Go 语言内部代码的参考资料,将非常有帮助。

编辑 1:这是我在学习 defer 后尝试的练习 https://go.dev/tour/moretypes/26


<details>
<summary>英文:</summary>

package main

import "fmt"

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
a, b := 0, 1
return func() int {
defer func() {a, b = b, a + b}()
return a
}
}

func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}


Can someone explain why the output starts from 0, 1, 1, 2, 3, 5 .... instead of 1, 1, 2, 3, 5, .....?

As I understand defer would be executed before return statement which means a, b is updated to 1, 1 already and 1 should be returned? Maybe it has something to do with when the expression is evaluated or binded, maybe the return has already binded a as 0 and then check just before returning if defer statements are there?

Any internal code reference in go would be highly helpful.

Edit 1: This is from the exercise https://go.dev/tour/moretypes/26 which I tried after learning about defer.

</details>


# 答案1
**得分**: 1

有人能解释一下为什么输出从0、1、1、2、3、5...开始,而不是1、1、2、3、5...吗?

如果包围的函数通过显式的return语句返回,延迟函数会在该return语句设置结果参数之后执行,但在函数返回给调用者之前执行。
[延迟语句](https://go.dev/ref/spec#Defer_statements)

这是因为延迟函数执行并将a的值从0更改为1,但a的值已经是返回值。


    func fibonacci() func() int {
        a, b := 0, 1
        return func() int {
            defer func() {a, b = b, a + b}()
            return a
        }
    }

<details>
<summary>英文:</summary>

&gt; Can someone explain why the output starts from 0, 1, 1, 2, 3, 5 ....
&gt; instead of 1, 1, 2, 3, 5, .....?

if the surrounding function returns through an explicit return statement, deferred functions are executed after any result parameters are set by that return statement but before the function returns to its caller
[Defer_statements](https://go.dev/ref/spec#Defer_statements)

Because the defer function executes and changes the value of a from 0 to 1 but the value of a is already the return explicit.


    func fibonacci() func() int {
        a, b := 0, 1
        return func() int {
            defer func() {a, b = b, a + b}()
            return a
        }
    }

</details>



# 答案2
**得分**: 1

`defer`在`return a`之后执行,此时已经无法更改局部变量`a`的值。

你可能将其与`defer`更改命名返回值混淆了。这是一个不同的情况,因为即使在`return`之后更改它,函数实际上也会返回它。

<details>
<summary>英文:</summary>

The `defer` gets executed after `return a` when it is too late to change the value of local variable `a`.

You are probably confusing it with `defer` changing a named return value. That&#39;s a different case because even changing it after `return`, the function will actually return it.

</details>



huangapple
  • 本文由 发表于 2022年4月27日 13:16:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/72023589.html
匿名

发表评论

匿名网友

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

确定