一、初识defer
func main(){
defer fmt.println("world")
fmt.println("hello")
}
==>hello
world
=>defer语句会在函数最后执行,被延迟操作的是defer后面的内容
二、特点
defer后面的表达式必须是外部函数的调用.上面的例子是针对fmt.println函数的延迟调用
1)只有当defer语句全部执行,defer所在的函数才能算真正结束执行
2)当函数中有defer语句时,需要等待所有defer语句执行完毕,才会执行return语句
=》defer常用于回收资源,清理收尾
func print(){
fmt.println("hello")
}
func main(){
for ;i<5;i++{
defer print()
}
}
==>5,5,5,5,5
func print(i int){
fmt.println(i)
}
func main(){
for ;i<5;i++{
defer print(i)
}
}
==>4,3,2,1,0(相当于先储存(0,1,2,3,4)),在输出(4,3,2,1,0)【这也是所谓的后进先出】
一道考察defer与命名返回值的题目
返回4,1,3
解释:
defer和return以及返回值的关系是defer最先执行一些收尾工作,然后return执行,return负责将结果写入返回值,最后函数携带当前返回值退出,所以:
func a()(i int){
defer funcA(){
}
defer funcB(){
}
}
先运行funcB再运行funcA
回到上面的代码,DeferFunc2 函数没有可命名结果形参,t只是个普通局部变量,defer无法对返回值做修改;DeferFunc1 和DeferFunc3的运行逻辑是:
DeferFunc1:
t:= 0
t = 1
t +=3 -> t = 4
DeferFunc3:
t:=0
t = 2
t += 1 -> t = 3
对于返回值是否命名关乎到main函数内调用其他含有defer的函数时,是否可以获取真实的返回值,即没命名返回0,有命名返回最后一次defer的输出。
三.代码跟踪
func main(){
b()
}
func a(){
defer un(trace("a")) //初始化defer函数的参数,所以输出trace()的结果
fmt.Println("a的逻辑代码")
}
func a(){
defer un(trace("a"))
fmt.Println("b的逻辑代码")
a()
}
func trace(s string)string{
fmt.Println("开始执行",s)
return s
}
func un(s string){
fmt.Println("结束执行",s)
}
=>开始执行b
b的逻辑代码
开始执行a
a的逻辑代码
结束执行a
结束执行b