上文我们讲了Go语法的特殊之处,本文讲述Go语法之函数 defer使用。

延迟调用defer是什么?

关键字 defer 的用法类似于面向对象编程语言 Java 和 C# 的 finally 语句块,它一般用于释放某些已分配的资源

  • defer用于注册一个延迟调用(在函数返回之前调用)。
  • defer典型的应用场景是释放资源,比如关闭文件句柄,释放数据库连接等。
  • 如果同一个函数里有多个defer,则后注册的先执行。
  • defer后可以跟一个func,func内部如果发生panic,会把panic暂时搁置,当把其他defer执行完之后再来执行这个。
  • defer后不是跟func,而直接跟一条执行语句,则相关变量在注册defer时被拷贝或计算。
func basic() {fmt.Println("A")defer fmt.Println(1) fmt.Println("B")//如果同一个函数里有多个defer,则后注册的先执行defer fmt.Println(2)fmt.Println("C")}
func defer_exe_time() (i int) {i = 9defer func() { //defer后可以跟一个funcfmt.Printf("first i=%d\n", i) //打印5,而非9。充分理解“defer在函数返回前执行”的含义,不是在“return语句前执行defer”}()defer func(i int) {fmt.Printf("second i=%d\n", i) //打印9}(i)defer fmt.Printf("third i=%d\n", i) //defer后不是跟func,而直接跟一条执行语句,则相关变量在注册defer时被拷贝或计算return 5}

关键字 defer 允许我们推迟到函数返回之前(或任意位置执行 return 语句之后)一刻才执行某个语句或函数(为什么要在返回之后才执行这些语句?因为 return 语句同样可以包含一些操作,而不是单纯地返回某个值)。

package mainimport "fmt" func main() {function1()} func function1() {fmt.Printf("In function1 at the top\n")defer function2()fmt.Printf("In function1 at the bottom!\n")} func function2() {fmt.Printf("function2: Deferred until the end of the calling function!")}

输出:

In Function1 at the topIn Function1 at the bottom!Function2: Deferred until the end of the calling function!

将 defer 关键字去掉并对比输出结果。
使用 defer 的语句同样可以接受参数,下面这个例子就会在执行 defer 语句时打印 0:

func a() {i := 0defer fmt.Println(i)i++return}

当有多个 defer 行为被注册时,它们会以逆序执行(类似栈,即后进先出):

func f() {for i := 0; i < 5; i++ {defer fmt.Printf("%d ", i)}}

上面的代码将会输出:4 3 2 1 0。

关键字 defer 允许我们进行一些函数执行完成后的收尾工作,例如:

关闭文件流 (详见 第 12.2 节)

// open a filedefer file.Close()

解锁一个加锁的资源

mu.Lock()defer mu.Unlock() 

打印最终报告

printHeader()defer printFooter()

关闭数据库链接

// open a database connectiondefer disconnectFromDB()