目录
在函数中,程序员经常需要创建资源(比如:数据库连接、文件句柄、锁等) ,为了在函数执行完毕后,及时的释放资源,Go 的设计者提供 defer (延时机制)。
package main
import "fmt"
func sum(n1 int,n2 int) int {
defer fmt.Println("ok1 n1=",n1)
defer fmt.Println("ok2 n2=",n2)//注意n1,n2的输出顺序,遵守出栈规则
res := n1 + n2
fmt.Println("ok3 res=",res)
return res
}
func main() {
res := sum(10,20)
fmt.Println("res=",res)
}
输出结果:
ok3 res= 30
ok2 n2= 20
ok1 n1= 10
res= 30
注意事项与细节
-
当 go 执行到一个 defer 时,不会立即执行 defer 后的语句,而是将 defer 后的语句压入到一个栈中, 然后继续执行函数下一个语句。
-
当函数执行完毕后,在从该栈中,依次从栈顶取出语句执行(遵守栈 先入后出的机制),
-
在 defer 将语句放入到栈时,也会将相关的值拷贝同时入栈。
-
defer 允许你把配套的两个行为代码放在最近相邻的两行,比如创建&释放资源、加锁&释放锁等,使得代码更易读,编程体验优秀。
defer的调用顺序
package main
import "fmt"
func deferFunc1(i int) (t int) {
t = i
defer func() {
t += 1
}()
return t
}
func deferFunc2(i int) int {
t := i
defer func() {
t += 1
}()
return t
}
func deferFunc3(i int) (t int) {
defer func() {
t += i
}()
return 1
}
func deferFunc4() (t int) {
defer func(i int) {
fmt.Println(i)
fmt.Println(t)
}(t)
t = 0
return 1
}
func main() {
// 猜猜下面输出的内容和顺序
fmt.Println(deferFunc1(1))
fmt.Println(deferFunc2(1))
fmt.Println(deferFunc3(1))
deferFunc4()
}
defer
是延迟函数,执行动作在return之后,defer相当于是将执行动作压入栈中,越是后面的defer越是先执行,执行顺序是LIFO(后进先出)。
特别指出:有函数返回值的则return将结果写入返回值,defer进行收尾,可以看做 return最先执行,然后return将结果存入返回值,最后defer执行
那么基于刚刚的介绍再回头去看得到的『实际结果是:2,1,2,0,1』
-
defer,return,return value(函数返回值) 执行顺序:首先return,其次return value,最后defer。defer可以修改函数最终返回值。