返回介绍

02.6 defer 关键字

发布于 2024-08-14 12:50:32 字数 9470 浏览 0 评论 0 收藏 0

defer关键字

defer关键字的作用是当外围函数返回之后才执行被推迟的函数。在文件输入输出操作中经常可以见到defer关键字,因为它使您不必记住何时关闭已打开的文件:defer关键字调用文件关闭函数关闭已打开的文件时,可以紧靠着文件打开函数之后。在第八章“告诉Unix系统要做什么”中,会介绍如何在文件相关操作中使用defer关键字,本节将介绍defer的其他用法。您还将在 panic()recover() 两个Go内置函数中看到defer操作。

首先记住一点重要的原则:defer函数在外围函数返回之后,以后进先出(LIFO)的原则执行。简单点说,在一个外围函数中有3个defer函数: f1() 最先出现,然后 f2() ,最后 f3() ,当外围函数执行返回之后, f3() 最先被执行,接着是 f2() ,最后是 f1()

如果你感觉这个定义不是很清晰,查看并执行 defer.go 源码,这应该会让你理解的更清楚些。下面分三部分呈现这段源码。

源码第一部分:

package main
import (
    "fmt"
)
func d1() {
    for i := 3; i > 0; i-- {
        defer fmt.Print(i, " ")
    }
}

上面的Go代码实现了一个名为 d1() 函数,函数里面有一个 for 循环和一个 defer 语句,这个 defer 语句将会执行三次。

第二部分源码:

> func d2() {
>     for i := 3; i > 0; i-- {
>         defer func() {
>             fmt.Print(i, " ")
>         }()
>     }
>     fmt.Println()
> }

这部分代码实现了 d2() 函数,它也包含了一个 for 循环和一个 defer 语句,这个 defer 语句也会执行三次,但是这个 defer 执行的是匿名函数,并且匿名函数没有带参数。

最后一部分源码:

> func d3() {
>     for i := 3; i > 0; i-- {
>         defer func(n int) {
>             fmt.Print(n, " ")
>         }(i)
>     }
> }
> func main() {
>     d1()
>     fmt.Println()
>     d2()
>     fmt.Println()
>     d3()
>     fmt.Println()
> }

这部分代码,定义了 d3() 函数,它包含了 for 循环 defer 语句,这个 defer 执行带参数的匿名函数,其中参数n使用的是循环中变量i的值。 main() 函数调用这三个函数。

执行源码会得到如下输出:

$ go run defer.go
1 2 3
0 0 0
1 2 3

您很可能会发现生成的输出很复杂且难以理解。 这表明,如果您的代码不清晰或不明确,执行 defer 操作可能会产生非常棘手的结果。

让我们分析一下上面的结果,更进一步了解如果不密切关注自己的代码, defer 将会变得多么棘手。第一行是 d1() 函数输出的(1 2 3),变量i的值在这个函数中顺序是3 、2和1 ,在 d1() 中延迟的函数是 fmt.Print() 。 因此,当 d1() 函数即将返回时,您将以相反的顺序获取for循环中变量i的三个值,因为被延迟的函数以 LIFO 顺序执行。

第二行是 d2() 函数的输出,很奇怪的是我们得到了单个0,而不是想象中的1、2和3 ,原因很简单,在循环结束后,i的值为0,因为是0值使循环终止。但是,这里棘手的部分是在循环结束后会执行被延迟的匿名函数。因为它没有参数,这意味着,将值为0的i进行三次打印输出! 在您的项目中,这种令人困惑的代码可能导致令人讨厌的错误,所以尽量避免它!

第三行是 d3() 函数的输出,因为匿名函数的参数的存在,每次匿名函数被推迟执行的时候,它都会获取并使用变量i当前的值,所以每次执行匿名函数都有不同的值输出。

到这里,你应该清楚了,使用 defer 的最好的方式就是第三个函数展示的方法,这是因为您故意以易于理解的方式在匿名函数中传递所需的变量。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文