defer: “延迟”,“推迟”
defer的作用:在go中,使用defer关键字来延迟一个函数或者方法的执行被延迟了。
如果一个函数使用了defer关键字,那么就会等主函数中所有程序执行完,在执行这个函数内的程序。
defer的用法:
- 对象.close()
一般来说defer常用于文件的读写,我们在打开文件的时候一般会使用文件.open(),但是我们可能很容易忘记close文件,那么我们可以在调用open函数时,用defer直接顺手调用好close()。 - go中关于异常的处理,通常使用panic()和recover()。
panic函数用于引发恐慌,导致程序中断执行;
recover函数用于恢复程序的执行。recover()语法上要求必须在defer中执行。
看一下下面两个例子
func fun(s string) {
fmt.Println(s)
}
func main() {
fmt.Println("hello")
fun("white")
fmt.Println("world")
}
func fun(s string) {
fmt.Println(s)
}
func main() {
fmt.Println("hello")
defer fun("white")
fmt.Println("world")
}
对比两个例子中小小的变化,可以发现defer在实际程序中就是起到延迟执行的作用。
那么当有多个defer函数时,到底谁将最后被执行呢?
看下面例子。
func fun(s string) {
fmt.Println(s)
}
func main() {
fmt.Println("hello")
defer fun("Mr.White")
fmt.Println("world")
defer fun("Mr.Black")
}
通过上面例子可以看出多个函数用defer定义时,即多个函数相当于被添加到了一个栈中。
而执行顺序为LIFO(先进后出)
所以多个defer函数:先延迟的后执行,后延迟的限制性
除此之外,defer函数传递参数的时候:defer函数调用时,就已经传递了参数数据,只是暂时不执行函数中的代码而已。
defer的注意点:
- 当外围函数中的语句正常执行完成时,只有其中所有的延迟函数都执行完毕,外围函数才会真正的结束执行。
- 当执行外围函数中的return语句时,只有其中所有的延迟函数都执行完毕后,外围函数才会真正返回。
- 当外围函数中的代码引发运行恐慌时,只有其中所有的延迟函数都执行完毕后,该运行时恐慌才会真正被扩展至调用函数。
前两点以及defer函数传参可以参考如下例子。
func fun(s string) {
fmt.Println(s)
}
func funNum(num int) {
fmt.Println("fun中的a:", num)
}
func funRun() int {
fmt.Println("funRun函数中的执行。。。")
defer fun("hihi")
return 0
}
func main() {
a := 2
fmt.Println(a)
defer funNum(a)
a++
fmt.Println("main中的a:", a)
funRun()
}