go语言中
defer
最主要的目的是在函数执行完毕后及时的释放资源
入门案例
package main
import "fmt"
func sum(n1 int, n2 int) int {
//当执行到defer时,会将defer后面的语句压入到独立的栈中(我们取名为defer栈吧)
//当函数执行完毕后,再从defer栈,先进后出的方式出栈然后执行
defer fmt.Println("ok1 n1=",n1) // 3. n1
defer fmt.Println("ok2 n2=",n2) //2. n2
res := n1 + n2 //res = 30,首先执行
fmt.Println("ok3 res=",res) // 1. res = n1 + n2
return res
}
func main(){
res := sum(10,20)
fmt.Println("main res=",res)
}
- main方法调用
sum
函数 - 代码执行到第一个
defer
后,编译器(系统)会将第一个defer
这段压入到defer的栈中
(暂时不执行)
注意事项
- 当ggo执行到一个
defer
时,不会立刻执行defer后的语句,而是将defer后的语句压入一个独立的栈中,然后继续执行函数下一条语句 - 当执行完毕后,再从
defer栈(只是为了理解这么叫,实际其实只是一个独立的栈)
,依次从栈顶取出语句执行(先进后出原则) - 在
defer
将语句放入栈时,也会将相关的值拷贝同时入栈(入栈时是什么值就是什么值)
package main
import "fmt"
func sum(n1 int, n2 int) int {
//当执行到defer时,会将defer后面的语句压入到独立的栈中(我们取名为defer栈吧)
//当函数执行完毕后,再从defer栈,先进后出的方式出栈然后执行
defer fmt.Println("ok1 n1=",n1) //n1 = 10
defer fmt.Println("ok2 n2=",n2) //n2 = 20
n1++ //添加代码: n1++
n2++ //添加代码: n2++
res := n1 + n2
fmt.Println("ok3 res=",res) //res = 32
return res
}
func main(){
res := sum(10,20)
fmt.Println("main res=",res) //结果还是会被影响 res = 32
}
结果
defer最佳实践
defer主要的价值是在当函数执行完毕后,可以及时释放函数创建的资源
//示意代码
func test(){
//关闭文件资源
file = openfile(文件名)
defer file.close()
//其他代码
//连接的数据库还是可以使用的
}
func test(){
//释放数据库资源
connect = openDatabase()
defer connect.close()
//其他代码
//连接的数据库还是可以使用的
}
- 在golang编程中的通常的做法是,创建资源后,比如(打开了文件,获取了数据库连接或者时锁等资源)可以执行
defer
语句来进行关闭(函数执行完后才从独立的栈中释放关闭资源) - 在
defer
后可以继续使用创建的资源 - 当函数执行完后,系统会依次从这个独立的栈中取出语句或关闭资源