Go的学习路程:defer 延迟执行函数|Go 主题月

584 阅读2分钟

Go 语言的 defer 语句会将其后面跟随的语句进行延迟处理。在 defer 所在的函数即将返回时,将延迟处理的语句按 defer 的逆序进行执行。类似栈的访问方式,先进后出。最先被 defer 的语句最后被执行,最后被 defer 的语句最先被执行。

Go 的 defer 的用法 与 Java 中的 finally 非常的相似。一般用来释放资源,比如文件句柄、数据库连接或者互斥锁等等。

defer 特性

  1. 关键字 defer 用于注册延迟调用
  2. 这些调用直到 return 前才被执。因此,可以用来做资源清理
  3. 多个defer语句,按先进后出的方式执行
  4. defer语句中的变量,在defer声明时就决定了

defer 用途

  1. 关闭文件句柄
  2. 锁资源释放
  3. 数据库连接释放

多个延迟语句的执行顺序

通过上面的介绍我们知道,defer 注册延迟处理函数与栈的访问方式非常的相似。秉承着先进后出的执行顺序。通过下面的程序验证一下。

package main

import "fmt"

func main () {
    fmt.Print("defer begin ")

    defer fmt.Print(" 1 ")
    defer fmt.Print(" 2 ")
    defer fmt.Print(" 3 ")

    fmt.Print(" defer end ")
}
  • 程序输出:defer begin defer end 3 2 1

通过程序输出结果可以看出,defer 后面的语句会在普通语句执行完成后才执行。并且是 defer 的逆序执行的。

defer 释放资源

使用之前的一个例子作为演示。代码 1 处将文件的关闭延迟处理。当函数执行完成即将返回时会将文件资源释放。

package main

import "fmt"
import "os"

func main () {
    f, err := os.Open("D:\\tmp\\hello.txt")

    if err != nil {
        fmt.Printf("打开文件错误,%v", err)
        return
    }
    defer f.Close() // 1

    buf := make([]byte, 8)
    for n, _ := f.Read(buf); n != 0; n, _ = f.Read(buf) {
        fmt.Printf("读取 %d byte 内容,内容:%q\n", n, buf[:n])
    }
}

defer 匿名函数

之前的例子都是 defer 延迟处理一个函数,defer 也可以延迟处理匿名函数,具体演示代码如下。

package main

import "fmt"

func main () {
    fmt.Print("defer begin ")

    defer func () {
        fmt.Print(" 1 ")
        fmt.Print(" 2 ")
        fmt.Print(" 3 ")
    }()

    fmt.Print(" defer end ")
}
  • 程序输出:defer begin defer end 1 2 3