首页 >企业动态 > > 正文

面试Go 被defer的几个盲区坑了_百事通

来源:程序员客栈 2023-03-06 23:45:53

大家好,我是二条,一位从事后端开发的程序员。

上一篇,我们了解了Go中的字符串为什么不能进行修改,这一篇分享关于defer语句中的6个必备知识点。这也是面试过程中,被问到的一个问题。

关于Go中的defer,是做什么的?执行顺序是怎么样的?相信学过Go语言的同学,已经不在陌生,今天就来讲讲其中需要掌握的几个知识点。


【资料图】

要讲到这几个知识点,还是大致总结一下defer这个内置关键字。

1、defer是一种延迟处理机制,是在函数进行return之前进行执行。

2、defer是采用栈的方式执行,也就是说先定义的defer后执行,后定义的defer最先被执行。

正因为defer具备这种机制,可以用在函数返回之前,关闭一些资源。例如在某些操作中,连接了MySQL、Redis这样的服务,在函数返回之前,就可以使用defer语句对连接进行关闭。就类似oop语言中的 finally操作一样,不管发生任何异常,最终都会被执行。

其语法格式也非常的简单。

packagemainimport"fmt"funcmain(){function1()}funcfunction1(){fmt.Printf("2")deferfunction2()fmt.Printf("1")}funcfunction2(){fmt.Printf("3")}

上述代码执行的结果是:

213

下面就来总结这六个小知识点:

1、defer 的执行顺序。采用栈的方式执行,先定义后执行。

2、defer 与 return 谁先谁后。return 之后的语句先执行,defer 后的语句后执行。

3、函数的返回值初始化与 defer 间接影响。defer中修改了返回值,实际返回的值是按照defer修改后的值进行返回。

4、defer 遇见 panic。按照defer的栈顺序,输出panic触发之前定义好的defer。

5、defer 中包含 panic。按照defer的栈顺序,输出panic触发之前的defer。并且defer中会接收到panic信息。

6、defer 下的函数参数包含子函数。会先进行子函数的结果值,然后在按照栈的顺序进行输出。

defer的执行顺序是什么样的

关于这个问题,前面的示例代码也提到过了,采用栈的顺序执行。在定义时,压入栈中,执行是从栈中获取。

defer与return谁先谁后

先来看如下一段代码,最终的执行结果是怎么样的。

funcmain(){fmt.Println(demo2())}funcdemo2()int{deferfunc(){fmt.Println("2")}()returnfunc()int{fmt.Println("1")return4}()}

运行上述代码,得到的结果是:

124

可能你会有一个疑问❓ ,既然都提到了defer是在函数返回之前执行,为什么还是先输出1,然后在输出2呢?关于defer的定义,就是在函数返回之前执行。这一点毋庸置疑,肯定是在return之前执行。需要注意的是,return 是非原子性的,需要两步,执行前首先要得到返回值 (为返回值赋值),return 将返回值返回调用处。defer 和 return 的执行顺序是先为返回值赋值,然后执行 defer,然后 return 到函数调用处。

函数的返回值初始化与defer间接影响

同样的方式,我们先看一段代码,猜测一下最终的执行结果是什么。

funcmain(){fmt.Println(demo3())}funcdemo3()(aint){deferfunc(){a=3}()return1}

上诉代码,最终的运行结果如下:

3

跟上第2个知识点类似,函数在return之前,会进行返回值赋值,然后在执行defer语句,最终在返回结果值。

1、在定义函数demo3()时,为函数设置了一个int类型的变量a,此时int类型初始化值默认是0。

2、定义一个defer语句,在函数return之前执行,匿名函数中对返回变量a进行了一次赋值,设置 a=3。

3、此时执行return语句,因为return语句是执行两步操作,先为返回变量a执行一次赋值操作,将a设置为3。紧接着执行defer语句,此时defer又将a设置为3。

4、最终return进行返回,由于第3步的defer对a进行了重新赋值。因此a就变成了3。

5、最后main函数打印结果,打印的其实是defer修改之后的值。

如果将变量a的声明放回到函数内部声明呢,其运行的结果会根据return的值进行返回。

funcmain(){fmt.Println(demo7())}funcdemo7()int{varaintdeferfunc(aint){a=10}(a)return2}

上述的最终结果返回值如下:

102

为什么会发生两种不同的结果呢?这是因为,这是因为发生了值拷贝现象。在执行defer语句时,将参数a传递给匿名函数时进行了一个值拷贝的过程。由于值拷贝是不会影响原值,因此匿名函数对变量a进行了修改,不会影响函数外部的值。当然传递一个指针的话,结果就不一样了。在函数定义时,声明的变量可以理解为一个全局变量,因此defer或者return对变量a进行了修改,都会影响到该变量上。

defer遇见panic。

panic是Go语言中的一种异常现象,它会中断程序的执行,并抛出具体的异常信息。既然会中断程序的执行,如果一段代码中发生了panic,最终还会调用defer语句吗?

funcmain(){demo4()}funcdemo4(){deferfunc(){fmt.Println("1")}()deferfunc(){fmt.Println("2")}()panic("panic")deferfunc(){fmt.Println("3")}()deferfunc(){fmt.Println("4")}()}

运行上述代码,最终得到的结果如下:

╰─gorundefer.go21panic:panicgoroutine1[running]:main.demo4()

从上面的结果不难看出,虽然发生了panic异常信息,还是输出了defer语句中的信息,这说明panic的发生,还是会执行defer操作。那为什么后面的两个defer没有被执行呢。这是因为pani的发生,会中断程序的执行,因此后续的代码根本没有拿到执行权。

当函数中发生了panic异常,会马上中止当前函数的执行,panic之前定义的defer都会被执行,所有的 defer 语句都会保证执行并把控制权交还给接收到 panic 的函数调用者。这样向上冒泡直到最顶层,并执行(每层的) defer,在栈顶处程序崩溃,并在命令行中用传给 panic 的值报告错误情况:这个终止过程就是 panicking。

defer中包含panic

上一个知识点提到了,程序中虽然发生了panic,但是在panic之前定义的defer语句,还是会被执行。要想在defer中获取到具体的panic信息,需要使用 recover()进行获取。

funcmain(){demo5()}funcdemo5(){deferfunc(){fmt.Println("1")iferr:=recover();err!=nil{fmt.Println(err)}}()deferfunc(){fmt.Println("2")}()panic("panic")deferfunc(){fmt.Println("defer:panic之后,永远执行不到")}()}

上述代码执行的结果如下:

21panic

这个(recover)内建函数被用于从 panic 或 错误场景中恢复:让程序可以从 panicking 重新获得控制权,停止终止过程进而恢复正常执行。

defer下的函数参数包含子函数

对于这种场景,可能大家很少遇见,也不是很清楚实际的调用逻辑。先来看一段代码。

funcmain(){demo6()}funcfunction(indexint,valueint)int{fmt.Println(index)returnindex}funcdemo6(){deferfunction(1,function(3,0))deferfunction(2,function(4,0))}

上诉代码最终执行的结果是:

3421

其执行的逻辑是:

1、执行第1个defer时,压入defer栈中,该defer会执行一个function的函数,在函数返回之前执行。

2、因为该函数中又包含了一个函数(子函数),Go语言处理的机制是,先执行该子函数。

3、执行完子函数,接着再执行第2个defer语句。此时,第2个defer中也有一个子函数,按照第2点的逻辑,这个子函数会被直接执行。

4、定义完defer语句之后,此时结束该函数的调用。所有被定义的defer语句,按照栈顺序进行输出。

因此可以得出的结论是,当defer中存在子函数时,子函数会按照defer定义的语句顺序,优先执行。defer最外层的逻辑,则按照栈的顺序执行。。

总结

对于defer的使用,是非常简单的。这里需要注意几点。

1、defer是在函数返回之前执行,defer的执行顺序是优先于return。return的执行是一个两步操作,先对return返回的值进行赋值,然后执行defer语句,最后将结果进行返回给函数的调用者。

2、即使函数内发生了panic异常,panic之前定义的defer仍然会被执行。

3、defer中存在子函数,子函数会按照defer的定于顺序执行。

上一篇: 下一篇:
x
推荐阅读

面试Go 被defer的几个盲区坑了_百事通

2023-03-06

请问西安孕婴用品批发市场

2023-03-06

低碳产业_世界动态

2023-03-06

当前时讯:济南地铁6号线最新消息!工业园站主体建设工程规划许可批前公示

2023-03-06

周刊虚拟歌手中文曲排行榜552·文字专栏版

2023-03-06

垠-播资讯

2023-03-06

学练优九年级下册数学答案安徽版2023_学练优九年级下册数学答案

2023-03-06

形容男人气质的词语2个字_形容男人气质的词语|今日热文

2023-03-06

冰山上的来客主题曲_当前聚焦

2023-03-06

南京高科“22南京高科SCP008”3月11日兑付,利率为2.08% 世界热资讯

2023-03-06

世界短讯!hao123上网导航百度_hao123网址导航设为主页

2023-03-06

每日消息!象棋女子甲级联赛河北队一马当先

2023-03-06

环球微速讯:微信怎么实名认证不需要银行卡_微信怎么实名认证

2023-03-06

肯德基墨西哥鸡肉卷里面有什么

2023-03-06

天天观热点:成人如何提高免疫力的最有效方法_成人如何提高免疫力

2023-03-06

云南旅游必去的景点 云南旅游值得一去的10个地方推荐 天天新视野

2023-03-05

鲜艳_xianyan

2023-03-05

全球快看点丨skp是什么商场?

2023-03-05

热点在线丨今日管理的核心是什么选择题_管理的核心

2023-03-05

喝橘子皮水皮肤会发黄吗_喝橘子皮水

2023-03-05

再活五百年歌词_歌曲再活五百年歌词

2023-03-05

翡翠观音的佩戴有什么讲究,翡翠观音有什么寓意?_全球最资讯

2023-03-05

“图兰”经济特区

2023-03-05

索尼考虑同三星电子联手,据悉将讨论半导体供应合作方案

2023-03-05

0度终极幻想4

2023-03-04

全国政协委员兰臻:有一分热 发一分光 让乡村教育“薪火相传”

2023-03-04

今天国际董秘回复:金杯银杯不如客户的口碑

2023-03-04

每日快播:“琴岛之眼”摩天轮

2023-03-04

闽侯县中小学生心理健康云平台_健康云平台_全球消息

2023-03-04

多芬是哪个国家的品牌_多芬到底是哪个国家的品牌

2023-03-04

【环球时快讯】乌鲁木齐流感疫苗是一年打一次吗

2023-03-02

世界快报:8k纸和a4纸一样大么图片对比yanzhoushi

2023-03-02

天天看点:Marks & Spencer 在 251 家门店推出 Bring Your Own Bag' click & connect 计划

2023-03-02

星叶_对于星叶简单介绍 环球快消息

2023-03-02

女生把戒指戴在中指是什么意思_戒指戴在中指是什么意思

2023-03-02

3月1日基金净值:国泰中证煤炭ETF最新净值2.3259,涨0.21% 环球报资讯

2023-03-02

八种快速存钱法 热推荐

2023-03-01

世界关注:乌能源公司:乌克兰电力系统已18天供电正常

2023-03-01

108好汉绰号及绰号来源_108好汉的名字及其绰号

2023-03-01

最后一代燃油车型 新款奥迪Q7谍照曝光 世界消息

2023-03-01

2023年上海市普通高校体育类专业考试招生实施办法公布

2023-03-01

万业企业:2021年全球离子注入机、刻蚀设备、薄膜沉积、热处理设备占晶圆制造设备价值量合计约达47%

2023-03-01

印钞厂在哪儿_中国印钞厂在哪里|每日快播

2023-03-01

无锡地铁4号线二期新区站在哪里? 天天聚看点

2023-03-01

中国电信与中兴通讯联合发布“云网核心能力”创新成果 全球聚焦

2023-03-01

全球新资讯:北京丰台马场路199号_北京市丰台区张家路口121号

2023-03-01

今日关注:俄圣彼得堡空域已恢复正常 普尔科沃机场曾一度停止起降航班

2023-03-01

宝可梦武士道好玩吗 宝可梦武士道玩法简介

2023-03-01

二嘎子在农村_二嘎子-环球看点

2023-02-28

世界最新:最美脚丫

2023-02-28

利元亨:拟定增募资不超33.1亿元用于华东光伏高端装备产业化项目等

2023-02-28

国家能源局电工证查询网站官网_国家能源局电工证查询

2023-02-28

环球视点!nPower充电器

2023-02-28

空心金子瘪了用热水烫可以修复吗_空心金子瘪了用热水烫

2023-02-28

a6的发动机是进口还是国产_进口a6用了什么发动机 全球热议

2023-02-28

【环球速看料】excel保留两位小数函数

2023-02-28

SHINEPOST_今日观点

2023-02-28

全球快看:Tiamat完成近千万美元A轮融资,将继续自研AI图像生成大模型

2023-02-28

天天最资讯丨“公务员招考三十五岁门槛松动”话题引关注 多地放宽部分岗位年龄限制

2023-02-28

环球新动态:ZZYVP氮封装置

2023-02-28

血战太平洋电影完整版_血战太平洋电影

2023-02-28

焦点热议:闲话上海|茉莉花剧场的高光时刻

2023-02-27

热点!iphone6怎么查看手机热点有谁用_iphone6怎么查看手机真伪

2023-02-27

20钢的性质_20 钢的用途_环球视讯

2023-02-27

王菲约定这首歌表达了什么_王菲催眠歌词的含义 它究竟表达的是么意思王菲催

2023-02-27

资讯:三穗县台烈镇中心幼儿园

2023-02-27

外媒猛夸小米13 Pro:徕卡联合设计重新定义手机摄影 环球播报

2023-02-27

2023中国飞盘联赛首站比赛落户成都|即时

2023-02-27

铭瑄主板怎么设置u盘启动项_铭瑄主板怎么设置u盘启动 今日播报

2023-02-27

小鸡炖蘑菇的做法|微速讯

2023-02-27

从火箭少女101到INTO1 哇唧唧哇难掩运营短板_微头条

2023-02-27

远近光灯交替叫双闪吗

2023-02-27

不屈之志斯卡手弩 天天速讯

2023-02-27

电信校园卡怎么激活_收到电信校园卡怎么激活

2023-02-27

环球报道:手机验证码平台_手机验证码短信平台

2023-02-26

就业证

2023-02-26

年供 1.45 亿度绿色电能,陕西最大山地光伏电站正式并网发电

2023-02-26

伊拉克经济学家:为摆脱美元控制 人民币结算很有必要

2023-02-26

曹晴

2023-02-26

环球报道:如何构建金字塔形四坡屋顶

2023-02-26

权威人士爆料!梅西加冕世界足球先生,FIFA隆重庆祝,打脸金球奖 世界最新

2023-02-26

天天热点评!中国人的修养

2023-02-26

检查艾滋病挂什么科只是查血吗_检查艾滋病挂什么科 当前头条

2023-02-26

中国文化·汉字

2023-02-25

最资讯丨河北衡水:12328热线畅通民意打造靓丽交通

2023-02-25

环球消息!小伙参军入伍前去理发店剪寸头,自称第一次剪这么短,网友:剪完以后更帅了!

2023-02-25

中央大道

2023-02-25

天天要闻:如何看待威少加盟快船?福克斯:我TM才不管谁在对面

2023-02-25

太丢人!800一次!浙江有人卖淫嫖娼,4天交易2次... 天天聚看点

2023-02-25

中远泷玺台

2023-02-25

总裁爹地不好惹上官娆_总裁爹地不好惹_世界即时

2023-02-25

环球速看:王路晴

2023-02-25

美式橄榄球规则简单介绍_美式橄榄球规则

2023-02-25

当前观察:本金和本息的区别_本金

2023-02-25

批发管理学

2023-02-24

邹平一中

2023-02-24

湖州公务接待严控人员数量:来宾10人以内陪餐不超过3人 焦点热文

2023-02-24

武汉二套房公积金贷款利率2023-全球微头条

2023-02-24

twins资料|快看

2023-02-24

洗车人家加盟代理_洗车人家

2023-02-24