go 语言中的 defer

说明#

Go语言中的defer语句会将其后面跟随的语句进行延迟处理。在defer归属的函数即将返回时,将延迟处理的语句按defer定义的逆序进行执行,也就是说,先被defer的语句最后被执行,最后被defer的语句,最先被执行。返回值=x –> 运行 defer –> RET指令

defer 使用场景#

由于defer语句延迟调用的特性,所以defer语句能非常方便的处理资源释放问题。比如:资源清理、文件关闭、解锁及记录时间等。

defer执行时机#

在Go语言的函数中return语句在底层并不是原子操作,它分为给返回值赋值和RET指令两步。而defer语句执行的时机就在返回值赋值操作后,RET指令执行前。

defer 例子#

试题1#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"fmt"
)

func main() {
fmt.Println("start")
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("end")
}

// 结果
start
end
3
2
1

试题2#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package main

import (
"fmt"
)

func f1() int {
x := 5
defer func() {
x++
}()
return x //返回值x=5 --> defer x=6 --> return 5
}

func f2() (x int) {
defer func() {
x++
}()
return 5 //返回值x=5 --> defer x=6 --> return x=6
}

func f3() (y int) {
x := 5
defer func() {
x++
}()
return x //返回值y=x=5 --> defer x=6 --> return y=5
}

func f4() (x int) {
defer func(x int) { // defer 中匿名函数中的x 是个副本
x++
}(x)
return 5 //返回值x=5 --> defer x=5, x(副本)=6 --> return x=5
}

func main() {
fmt.Println(f1())
fmt.Println(f2())
fmt.Println(f3())
fmt.Println(f4())
}

//
5
6
5
5

试题3#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import "fmt"

func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}

func main() {
x := 1
y := 2
defer calc("AA", x, calc("A", x, y))
x = 10
defer calc("BB", x, calc("B", x, y))
y = 20
}
// 1. defer calc("AA", 1, calc("A", 1, 2))
// 2. calc("A", 1, 2) --> "A" 1 2 3
// 3. x = 10 --> x =10, y=2
// 4. defer calc("BB", 10, calc("B", 10, 2))
// 5. calc("B", 10, 2) --> "B" 10 2 12
// 6. defer calc("BB", 10, 12) --> "BB" 10 12 22
// 7. defer calc("AA", 1, 3) --> "AA" 1 3 4
/*
结果
"A" 1 2 3
"B" 10 2 12
"BB" 10 12 22
"AA" 1 3 4
*/