How to understand `defer` in go language?

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

How to understand `defer` in go language?

问题

在godoc(https://blog.golang.org/defer-panic-and-recover)中有一个例子:

  1. 延迟函数可以读取和赋值给返回函数的命名返回值。

在这个例子中,延迟函数在包围函数返回后递增返回值i。因此,该函数返回2:

func c() (i int) {
    defer func() { i++ }()
    return i
}

我也写了一个小程序:

package main

import "fmt"

func b() int {
    i := 0
    for ; i < 4; i++ {
        defer func() {fmt.Println(i); i++} ()
    }
    return i
}
func main() {
  fmt.Println("result =", b())
}

输出结果为:

4
5
6
7
result = 4

所以我很困惑,为什么第二个例子没有输出8

英文:

In the godoc(https://blog.golang.org/defer-panic-and-recover), there is an example:

> 3. Deferred functions may read and assign to the returning function's named return values.
>
> In this example, a deferred function increments the return value i
> after the surrounding function returns. Thus, this function returns 2:

func c() (i int) {
    defer func() { i++ }()
    return i
}

I also wrote a small progam:

package main

import &quot;fmt&quot;

func b() int {
    i := 0
    for ; i &lt; 4; i++ {
        defer func() {fmt.Println(i); i++} ()
    }
    return i
}
func main() {
  fmt.Println(&quot;result = &quot;, b())
}

the output is:

4
5
6
7
result =  4

So I am confused, why does the second example not output 8 ?

答案1

得分: 10

请注意这部分内容:“可能会读取并分配给返回函数的命名返回值”。

这意味着:

func b() int {
    var i int
    defer func() { fmt.Println(i); i++ }()
    return i
}

将输出0result = 0,而:

func b() (i int) {
    defer func() { fmt.Println(i); i++ }()
    return i
}

将输出0result = 1

可以这样理解,我的第一个示例中的return ii的值分配给一个隐藏的返回变量(因为它没有命名),然后继续执行defer语句(只修改局部变量i),而在第二个示例中,我们直接将值分配给返回变量(因为它有命名),所以defer语句可以修改它。

基本上,你的程序可以这样解释:

package main

import "fmt"

func b() (hiddenVariable int) {
    i := 0
    for ; i < 4; i++ {
        defer func() { fmt.Println(i); i++ }()
    }
    hiddenVariable = i; return // 隐含的 return i 的意思
}

func main() {
    fmt.Println("result =", b())
}
英文:

Note the part that says "may read and assign to the returning function's named return values."

This means that:

func b() int {
    var i int
    defer func() { fmt.Println(i); i++ }()
    return i
}

will say 0 and result = 0, while:

func b() (i int) {
    defer func() { fmt.Println(i); i++ }()
    return i
}

will say 0 and result = 1.

It might help to imagine that the return i in my first example assigns the i value to a hidden return variable (because it's not named), then goes on to execute the defer statements (which only modify the local variable i), while in the second example we assign directly to the return variable (because it's named) and so the defer statement is able to change it.

Basically your program could be interpreted like this:

package main

import &quot;fmt&quot;

func b() (hiddenVariable int) {
	i := 0
	for ; i &lt; 4; i++ {
		defer func() { fmt.Println(i); i++ }()
	}
	hiddenVariable = i; return // implicit meaning of return i
}

func main() {
	fmt.Println(&quot;result = &quot;, b())
}

答案2

得分: 0

根据我对defer的了解以及查看你的代码,我想说for循环推迟了后续的'i'的打印输出,但是for循环仍然运行,因此影响了由func b()返回的'i',它的值是4。

for ; i < 4; i++ {
    defer func() {fmt.Println(i); i++} ()
}
return i

由于打印语句及其对'i'的值的推迟,它们会递增超过4,但是for循环后面的'i'仍然保持为4。

英文:

Based solely on what I learned about defer and after looking at your code, I'd like to say that the for loop defers the print out of subsequent 'i's until later, however, the for loop still runs and therefore affects the 'i' returned by
func b(), which is 4.

for ; i &lt; 4; i++ {
    defer func() {fmt.Println(i); i++} ()
}
return i

Because the print statement and it's 'value' for 'i' is deferred, they increment beyond 4, but the 'i' after the for loop remains at 4.

答案3

得分: 0

defer语句将一个函数调用推入一个列表中。保存的函数调用列表会在包围函数返回后执行。你的**func b()**在语义上等同于:

func b() int {
    i := 0
    for ; i < 4; i++ {
    }
    ret := i
    fmt.Println(i); i++
    fmt.Println(i); i++
    fmt.Println(i); i++
    fmt.Println(i); i++
    return ret
}

因此,b()返回4。

英文:

A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. Your func b() is semantically equivalent to:

func b() int {
    i := 0
    for ; i &lt; 4; i++ {
    }
    ret := i
    fmt.Println(i); i++
    fmt.Println(i); i++
    fmt.Println(i); i++
    fmt.Println(i); i++
    return ret
}

Ergo b() returns 4.

huangapple
  • 本文由 发表于 2016年11月23日 11:02:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/40755315.html
匿名

发表评论

匿名网友

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

确定