Go语言中文网,致力于每日分享编码、开源等知识,欢迎关注我,会有意想不到的收获!
什么是 defer?
defer 语句的用途是:含有 defer 语句的函数,会在该函数将要返回之前,调用另一个函数。这个定义可能看起来很复杂,我们通过一个示例就很容易明白了。
示例
上面的程序很简单,就是找出一个给定切片的最大值。largest 函数接收一个 int 类型的切片作为参数,然后打印出该切片中的最大值。largest 函数的第一行的语句为 defer finished()。这表示在 finished() 函数将要返回之前,会调用 finished() 函数。运行该程序,你会看到有如下输出:
largest 函数开始执行后,会打印上面的两行输出。而就在 largest 将要返回的时候,又调用了我们的延迟函数(Deferred Function),打印出 Finished finding largest 的文本。
延迟方法
defer 不仅限于函数的调用,调用方法也是合法的。我们写一个小程序来测试吧。
在上面的例子中,我们在第 22 行延迟了一个方法调用。而其他的代码很直观,这里不再解释。该程序输出:
Welcome John Smith
实参取值(Arguments Evaluation)
在 Go 语言中,并非在调用延迟函数的时候才确定实参,而是当执行 defer 语句的时候,就会对延迟函数的实参进行求值。
通过一个例子就能够理解了。
在上面的程序里的第 11 行,a 的初始值为 5。在第 12 行执行 defer 语句的时候,由于 a 等于 5,因此延迟函数 printA 的实参也等于 5。接着我们在第 13 行将 a 的值修改为 10。下一行会打印出 a 的值。该程序输出:
从上面的输出,我们可以看出,在调用了 defer 语句后,虽然我们将 a 修改为 10,但调用延迟函数 printA(a)后,仍然打印的是 5。
defer 栈
当一个函数内多次调用 defer 时,Go 会把 defer 调用放入到一个栈中,随后按照后进先出(Last In First Out, LIFO)的顺序执行。
我们下面编写一个小程序,使用 defer 栈,将一个字符串逆序打印。
在上述程序中的第 11 行,for range 循环会遍历一个字符串,并在第 12 行调用了 defer fmt.Printf("%c