Go 中的 Defer 语句

Defer 是 Go 语言中一个比较有特色的语句,本文讲解如何理解 defer。

基本用法

Defer 语句提供了一种在函数执行完成后执行某代码或代码段的机制,我们先来看下面的例中:

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

import "fmt"

func sample1(a int, b int) int {

defer fmt.Println("sample1 has been finished")

fmt.Printf("Will return %d\n", (a + b))
return a + b
}

func main() {

fmt.Println("main Start...")
res := sample1(1, 2)
fmt.Printf("a + b = %d\n", res)
fmt.Println("End main.")
}

如果运行该程序,我们将得到如下的结果:

1
2
3
4
5
main Start...
Will return 3
sample1 has been finished
a + b = 3
End main.

可以看到,我们用 defer 指定的语句 fmt.Println(“sample1 has been finished”) 在函数返回后被执行了,更准确的是在 return 语句之后被执行了。

Defer 一个函数

Defer 后面除了直接跟语句,也可以根一个函数,效果是一样的。看下面的样例代码:

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

import "fmt"

func postFunc() {
fmt.Println("postFunc has been executed.")
}

func sample2(a int, b int) int {

defer postFunc()

fmt.Printf("Will return %d\n", (a + b))
return a + b
}

func main() {

fmt.Println("main Start...")
res := sample2(1, 2)
fmt.Printf("a + b = %d\n", res)
fmt.Println("End main.")
}

执行以后获得如下结果:

1
2
3
4
5
main Start...
Will return 3
postFunc has been executed.
a + b = 3
End main.

Defer 一个方法

在 Go 语言中,函数指的是没有与任何类型相关的代码段,而方法指的是依附于某个特定类型的代码段。

Defer 也可以用来延后执行一个方法。看下面的代码:

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
package main

import "fmt"

type Person struct {
FirstName string
LastName string
}

func (p Person) show() {
fmt.Printf("%s %s\n", p.LastName, p.FirstName)
}

func sample3() {

p := Person{
FirstName: "tom",
LastName: "H",
}
defer p.show()
fmt.Println("sample3 finished")
}

func main() {

fmt.Println("main Start...")
sample3()
fmt.Println("End main.")
}

执行程序后,可以得到如下结果:

1
2
3
4
main Start...
sample3 finished
H tom
End main.

捕获参数

defer 的函数可以带参数,看下面的代码:

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

import "fmt"

func show(val int) {
fmt.Printf("val is %d\n", val)
}

func sample4() int {

a := 0
defer show(a)

a = 100
return a
}

func main() {

fmt.Println("main Start...")
res := sample4()
fmt.Printf("in main, res = %d\n", res)
fmt.Println("End main.")
}

执行以后输出:

1
2
3
4
main Start...
val is 0
in main, res = 100
End main.

注意: 参数捕获的值是在函数中执行到 defer 语句时的值,不是最终的值,val = 0 而不是 100

多个 defer 的执行顺序

在一个函数中可以多次使用 defer 语句,那么当函数执行完以后,这些 defer 的语句又是以什么样的顺序被执行呢?

看下面的代码:

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

import "fmt"

func show(val int) {
fmt.Printf("val is %d\n", val)
}

func sample5() int {

a := 0
for ; a < 5; a++ {
defer show(a)
}
return a
}

func main() {

fmt.Println("main Start...")
res := sample5()
fmt.Printf("in main, res = %d\n", res)
fmt.Println("End main.")
}

执行这段程序,得到的结果如下:

1
2
3
4
5
6
7
8
main Start...
val is 4
val is 3
val is 2
val is 1
val is 0
in main, res = 5
End main.

可以看到,多个 defer 形成了一个栈式的调用,先进后出。最后的 defer 在函数执行完以后被最先调用。

本文标题:Go 中的 Defer 语句

文章作者:Morning Star

发布时间:2020年04月06日 - 15:04

最后更新:2021年04月16日 - 15:04

原始链接:https://www.mls-tech.info/golang/go-defer-statement/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。