如何理解go语言中的"defer"?

Bla*_*mba 4 go

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

  1. 延迟函数可以读取并分配给返回函数的命名返回值.

在此示例中,延迟函数在周围函数返回后递增返回值i.因此,此函数返回2:

func c() (i int) {
    defer func() { i++ }()
    return i
}
Run Code Online (Sandbox Code Playgroud)

我还写了一个小程序:

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())
}
Run Code Online (Sandbox Code Playgroud)

输出是:

4
5
6
7
result =  4
Run Code Online (Sandbox Code Playgroud)

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

Bli*_*ixt 9

请注意"可以读取并分配给返回函数的命名返回值 "的部分.

这意味着:

func b() int {
    var i int
    defer func() { fmt.Println(i); i++ }()
    return i
}
Run Code Online (Sandbox Code Playgroud)

会说0result = 0,同时:

func b() (i int) {
    defer func() { fmt.Println(i); i++ }()
    return i
}
Run Code Online (Sandbox Code Playgroud)

会说0result = 1.

可能有助于想象return i在我的第一个示例中将i值分配给隐藏的返回变量(因为它未命名),然后继续执行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 // implicit meaning of return i
}

func main() {
    fmt.Println("result = ", b())
}
Run Code Online (Sandbox Code Playgroud)