如何理解go语言中的“defer”?

时间:2016-11-23 03:02:38

标签: go

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

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

    在此示例中,延迟函数递增返回值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

3 个答案:

答案 0 :(得分:9)

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

这意味着:

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 // implicit meaning of return i
}

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

答案 1 :(得分:0)

完全基于我所了解的延迟和查看代码之后,我想说for循环将打印延迟到后续版本,直到稍后, for循环仍在运行,因此会影响“我”。归来的 func b(),即4。

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

因为印刷声明及其价值&#39;因为我是&#39;推迟,他们增加超过4,但是&#39; i&#39;在for循环保持在4之后。

答案 2 :(得分:0)

import shutil import datetime import os SOURCE = "C:/Program Files(x86) /FOLDER1/LOGS" AppendDate=datetime.datetime.now() BACKUP = "C:/Users/ME/Desktop/FOLDERNEW/LOGS %s" % AppendDate shutil.copytree(SOURCE,BACKUP) print os.listdir(BACKUP) 您的 func b()在语义上等同于:

A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns.

Ergo b()返回4.