defer语句
defer语句是go语言提供的一种用于注册延迟调用的机制,是go语言中一种很有用的特性。
9.1、defer的用法
defer语句注册了一个函数调用,这个调用会延迟到defer语句所在的函数执行完毕后执行,所谓执行完毕是指该函数执行了return语句、函数体已执行完最后一条语句或函数所在协程发生了恐慌。
fmt.Println("test01")
defer fmt.Println("test02")
fmt.Println("test03")
编程经常会需要申请一些资源,比如数据库连接、打开文件句柄、申请锁、获取可用网络连接、申请内存空间等,这些资源都有一个共同点那就是在我们使用完之后都需要将其释放掉,否则会造成内存泄漏或死锁等其它问题。但操作完资源忘记关闭释放是正常的,而defer可以很好解决这个问题
// 打开文件
file_obj,err:=os.Open("满江红")
if err != nil {
fmt.Println("文件打开失败,错误原因:",err)
}
// 关闭文件
defer file_obj.Close()
// 操作文件
9.2、多个defer执行顺序
当一个函数中有多个defer语句时,会按defer定义的顺序逆序执行,也就是说最先注册的defer函数调用最后执行。
fmt.Println("test01")
defer fmt.Println("test02")
fmt.Println("test03")
defer fmt.Println("test04")
fmt.Println("test05")
9.3、defer的拷贝机制
// 案例1
foo := func() {
fmt.Println("I am function foo1")
}
defer foo()
foo = func() {
fmt.Println("I am function foo2")
}
// 案例2
x := 10
defer func(a int) {
fmt.Println(a)
}(x)
x++
// 案例3
x := 10
defer func() {
fmt.Println(x) // 保留x的地址
}()
x++
当执行defer语句时,函数调用不会马上发生,会先把defer注册的函数及变量拷贝到defer栈中保存,直到函数return前才执行defer中的函数调用。需要格外注意的是,这一拷贝拷贝的是那一刻函数的值和参数的值。注册之后再修改函数值或参数值时,不会生效。