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 在函数执行完以后被最先调用。