首页 > 编程笔记

Go语言defer语句的用法

Go语言除了传统的流程控制语句外,还有一些特殊的控制语句,defer 就是其中之一。

defer 主要用于延迟调用指定的函数,defer 关键字只能出现在函数的内部,例如:
package main
import "fmt"
func main() {
    defer fmt.Println("world")
    fmt.Println("hello")
}
运行结果如下:
hello
world

在以上代码中会首先打印 hello,然后打印 world,因为第一句使用了 defer 关键字,defer 语句会在函数最后执行,被延迟的操作是 defer 后面的内容。

defer 后面的表达式必须是外部函数的调用,上面的例子就是针对 fmt.Println 函数的延迟调用。

Go语言 defer 语句有如下两大特点:
因为 defer 的延迟特点,可以把 defer 语句用于回收资源、清理收尾等工作。使用 deter 语句之后,不用纠结回收代码放在哪里,反正都是最后执行。

这里需要注意 defer 的执行时机,例如:
package main
import "fmt"
var i = 0
func print() {
   fmt.Println(i)
}
func main() {
   for ; i < 5; i++ {
       defer print()
   }
}
运行结果如下:
5
5
5
5
5

在以上代码中,返回了 5 个 5,这是因为每个 defer 都是在函数轮询之后才执行,此时 i 的值为 5。

如需要正确反向打印数字,Go语言代码如下:
package main
import "fmt"
var i = 0
func print(i int) {
    fmt.Println(i)
}
func main() {
    for ; i < 5; i++ {
        defer print(i)
    }
}
运行结果如下:
4
3
2
1
0

当 i 等于 0 时,defer 语句第一次被压栈,此时 defer 后面的函数返回 0;i 不断自增,一直到 i 等于 4 时,defer 语句第 5 次入栈,defer 后的函数返回 4;此时 i 的自增不再满足 for 条件,于是跳出循环,在结束之前,Go语言会根据 defer 后进先出原则逐条打印栈内的数值,因此就看到了现在的结果。

推荐阅读