go语言defer深入理解

前言:连续2天转多篇Go语言基础,这也正常,刚学嘛,转载别人的,不发原创总是对的,这不,我忍不住了,上篇自己原创的思考吧!

Go语言之defer

来看下官方定义
A “defer” statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because the surrounding function executed a return statement, reached the end of its function body, or because the corresponding goroutine is panicking.

emm……不知道你看懂了么,不准查翻译哦,给出我个人的理解

defer语句其实就是一个函数调用,只不过这个调用有点特殊,它不会立即执行,会延迟到defer语句所在的函数快要执行完毕后执行

何为快要执行完毕后执行呢?文字总是表达不不够到位,难以理解,看下代码吧。

package main
import "fmt"
//defer深入理解  https://haosy.blog.csdn.net/
func main() {    
fmt.Println("开始")    
defer fmt.Println("Do……")   
fmt.Println("结束")
}

在这里插入图片描述
可以看到,defer fmt.Println("Do……")发生了延迟,等待函数块(这里指main函数)执行完其它语句再执行。

那么,读者你可能要想要如果不是一个defer呢?而是多个defer呢?那么当函数块执行完其它语句后,这多个defer的执行顺序又是什么呢?多个defer的执行顺序为:后进先出,先进后出(遵循栈结构)

package main
import "fmt"
//defer深入理解  https://haosy.blog.csdn.net/
func main(){    
fmt.Println("开始")   
defer fmt.Println("Do……第1个进入的")  
defer fmt.Println("Do……第2个进入的") 
defer fmt.Println("Do……第3个进入的")
fmt.Println("结束")
}

在这里插入图片描述
defer语言能用到哪里呢?

因defer语句延迟调用的特性(会延迟到defer语句所在的函数快要执行完毕后执行),所以defer语句能非常方便的处理资源释放问题。比如:资源清理、文件关闭、解锁及记录时间等

等等等等,你以为defer你这就学会了么?测试一下自己,如果做对了,下文就不用再看了,如果做的不对,那么我这篇文章的正文对你而说才正式开始!

package main

import "fmt"

func f1() int {    
x := 4    
defer func() {        
x++    
}()    
return x
}

func f2() (x int) {    
defer func() {        
x++    
}()    
return 4
}

func f3() (y int) {    
x := 4    
defer func() {        
x++    
}()    
return x
}

func f4() (x int) {    
defer func(x int) {        
x++    
}(x)    
return 4
}

func main() {    
fmt.Println("f1()的结果为:", f1())    
fmt.Println("f2()的结果为:", f2())    
fmt.Println("f3()的结果为:", f3())    
fmt.Println("f4()的结果为:", f4())
}

你说结果是多少呢?
在这里插入图片描述
如果你答对了,恭喜你,掌握了,可以转身离开了,如果答错了,就看下述正文。(偷偷告诉你,我第一次做,第二次做都答错了,这不丢脸)

知识补充,Go语言中的return语句

在Go语言的函数中return语句在底层并不是原子操作,它分为给返回值赋值和RET指令两步。而defer语句执行的时机就在返回值赋值操作后,RET指令执行前。具体如下图所示:
在这里插入图片描述
有点绕口哈,什么意思呢?就是说 return x 不是一个原子操作,而是拆开的,先给返回值x赋值,defer,然后再ret,而正是因为如此(做错题可能就是因为这里不清楚)。

分析上文测试题

func f1() int {    
x := 4    
defer func() {        
x++    
}()    
return x
}

可以看到x:=4,然后reutn x ,给返回值赋值4,然后去执行defer,这个时候x++,x变成了5,但是可以看到func f1() int {这里并没有给返回值命名,也就是说 返回值 还是一开始赋予的4,defer修改的只是x的值,而不是返回值的值。相信给你绕晕了,不要着急,你继续往下看,把所有例题都看完,回过头来,你就明白了。f1()的结果为: 4

func f2() (x int) {    
defer func() {        
x++    
}()    
return 4
}

可以看到 return 4,再看下这个func f2() (x int),此函数给返回值命名为x了,那么return 4 实际是什么呢?
返回值为4,把4赋予给了x,然后去执行defer,x++,这x不就是返回值的x么,所以x变成了5,也就是返回值变成了5,怎么样,哈哈,我骗你了?是不是更迷糊了,不要着急,如果例子都看完,还迷糊,我就去吃一口土,只要你留言,我就吃。f2()的结果为: 5

func f3() (y int) {    
x := 4    
defer func() {       
x++    
}()    
return x
}

可以看到func f3() (y int) {,此函数给返回值命名为y了,那么,刚开始 x:=4,执行return x,也就是给返回值y赋值4,然后去执行defer,可是你看到了么?这defer中修改的都是x,和y没有关系啊,也就是和返回值没有关系啊,y的值(返回值)没有变动,还是4f3()的结果为: 4

func f4() (x int) {   
defer func(x int) {        
x++    
}(x)    
return 4
}

可以看到func f4() (x int),此函数给返回值命名为x了,那么这里的return 4 不就是 返回值=x=4么,然后去执行defer,有趣的是看到了么,defer…{}(x),把x当作参数传进去了,值类型,参数发生了修改,原本的值是不会修改的(改变的是defer函数中x的副本),所以返回值也就没有发生变动还是4f4()的结果为: 4

舒舒服服,懂了没?加把劲再来几道题吧!你可别走,看完再走也不迟!

//传一个指针到匿名函数中
func f5() (x int) {    
defer func(x *int) {        
(*x)++    
}(&x)    
return 4 //1.返回值=x=4  2.defer x=5 3.RET返回
}

不过多分析了,f5()和f4()可以看到一个是值传进去了,一个是指针传进去了,引用类型和值类型如果你懂的话,这里不用过多分析f5()的结果为: 5

留下来一道面试题,在评论区留出你的答案吧

func calc(index string, a, b int) int {
	ret := a + b
	fmt.Println(index, a, b, ret)
	return ret
}

func main() {
	x := 1
	y := 2
	defer calc("AA", x, calc("A", x, y))
	x = 10
	defer calc("BB", x, calc("B", x, y))
	y = 20
}

问,上面代码的输出结果是?(提示:defer注册要延迟执行的函数时该函数所有的参数都需要确定其值)

发布了57 篇原创文章 · 获赞 143 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_43518645/article/details/104234831