分享

Go 语言系列20:defer 延迟调用

 菜籽爱编程 2022-04-27

含有 defer 语句的函数,会在该函数将要返回之前,调用另一个函数。简单点说就是 defer 语句后面跟着的函数会延迟到当前函数执行完后再执行。

下面是一个简单的例子:

package main

import "fmt"

func myPrint() {
 fmt.Println("Go")
}

func main() {
 defer myPrint()
 fmt.Println("Let's")
}

首先,执行 main 函数,因为 myPrint() 函数前有 defer 关键字,所以会在执行完 main 函数后再执行 myPrint() 函数,所以先打印出 Let's ,再执行 myPrint() 函数打印 Go 。运行该程序输出如下:

Let's
Go

上面的程序等价于下面的程序:

defer fmt.Println("Go")
fmt.Println("Let's")


即时求值的变量快照

使用 defer 只是延时调用函数,传递给函数里的变量,不应该受到后续程序的影响。

str := "Go"
defer fmt.Println(str)
str = "Let's"
fmt.Println(str)

同理,运行该程序会输出如下:

Let's
Go


延迟方法

defer 不仅能够延迟函数的执行,也能延迟方法的执行。

package main

import "fmt"

type Person struct {
 firstName, lastName string
}

func (p Person) printName() {
 fmt.Printf("%s %s", p.firstName, p.lastName)
}

func main() {
 p := Person{"John""Smith"}
 defer p.printName()
 fmt.Printf("Hello ")
}

运行该程序输出如下:

Hello John Smith


defer 栈

当一个函数内多次调用 defer 时,Go 会把 defer 调用放入到一个栈中,随后按照 后进先出(Last In First Out, LIFO) 的顺序执行。

package main

import "fmt"

func main() {
 defer fmt.Printf("Caizi.")
 defer fmt.Printf("am ")
 defer fmt.Printf("I ")
 fmt.Printf("Hello! ")
}

运行上面的程序输出如下:

Hello! I am Caizi.


defer 在 return 后调用

看看下面的例子你就知道了:

package main

import "fmt"

var x int = 100

func myfunc() int {
 defer func() {x = 200}()
 fmt.Println("myfunc: x =", x)
 return x
}

func main() {
 myx := myfunc()
 fmt.Println("main: x =", x)
 fmt.Println("main: myx =", myx)
}

运行该程序输出如下:

myfunc: x = 100
main: x = 200
main: myx = 100


defer 可以使代码更简洁

如果没有使用 defer ,当在一个操作资源的函数里调用多个 return 时,每次都得释放资源,你可能这样写代码:

func f() {
    r := getResource()  //0,获取资源
    ......
    if ... {
        r.release()  //1,释放资源
        return
    }
    ......
    if ... {
        r.release()  //2,释放资源
        return
    }
    ......
    if ... {
        r.release()  //3,释放资源
        return
    }
    ......
    r.release()     //4,释放资源
    return
}

有了 defer 之后,你可以简洁地写成下面这样:

func f() {
    r := getResource()  //0,获取资源

    defer r.release()  //1,释放资源
    ......
    if ... {
        ...
        return
    }
    ......
    if ... {
        ...
        return
    }
    ......
    if ... {
        ...
        return
    }
    ......
    return
}

参考文献:

[1] Alan A. A. Donovan; Brian W. Kernighan, Go 程序设计语言, Translated by 李道兵, 高博, 庞向才, 金鑫鑫 and 林齐斌, 机械工业出版社, 2017.

👇周一至周五更新,期待你的关注👇

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多