前言

在golang当中,defer代码块会在函数调用链表中增加一个函数调用。这个函数调用不是普通的函数调用,而是会在函数正常返回,也就是return之后添加一个函数调用。因此,defer通常用来释放函数内部变量。
为了更好的学习defer的行为,我们首先来看下面一段代码:
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
dst, err := os.Create(dstName)
if err != nil {
return
}
written, err = io.Copy(dst, src)
dst.Close()
src.Close()
return
}
这段代码可以运行,但存在'安全隐患'。如果调用dst, err := os.Create(dstName)失败,则函数会执行return退出运行。但之前创建的src(文件句柄)没有被释放。 上面这段代码很简单,所以我们可以一眼看出存在文件未被释放的问题。 如果我们的逻辑复杂或者代码调用过多时,这样的错误未必会被及时发现。 而使用defer则可以避免这种情况的发生,下面是使用defer的代码:
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}
通过defer,我们可以在代码中优雅的关闭/清理代码中所使用的变量。defer作为golang清理变量的特性,有其独有且明确的行为。以下是defer三条使用规则。
规则一 当defer被声明时,其参数就会被实时解析
我们通过以下代码来解释这条规则:
func a() {
i := 0
defer fmt.Println(i)
i++
return
}
上面我们说过,defer函数会在return之后被调用。那么这段函数执行完之后,是不用应该输出1呢?
读者自行编译看一下,结果输出的是0. why?
这是因为虽然我们在defer后面定义的是一个带变量的函数: fmt.Println(i) . 但这个变量(i)在defer被声明的时候,就已经确定其确定的值了。 换言之,上面的代码等同于下面的代码:
func a() {
i := 0
defer fmt.Println(0) //因为i=0,所以此时就明确告诉golang在程序退出时,执行输出0的操作
i++
return
}
为了更为明确的说明这个问题,我们继续定义一个defer:
func a() {
i := 0
defer fmt.Println(i) //输出0,因为i此时就是0
i++
defer fmt.Println(i) //输出1,因为i此时就是1
return
}
通过运行结果,可以看到defer输出的值,就是定义时的值。而不是defer真正执行时的变量值(很重要,搞不清楚的话就会产生于预期不一致的结果)
但为什么是先输出1,在输出0呢? 看下面的规则二。
规则二 defer执行顺序为先进后出
当同时定义了多个defer代码块时,golang安装先定义后执行的顺序依次调用defer。不要为什么,golang就是这么定义的。我们用下面的代码加深记忆和理解:
func b() {
for i := 0; i < 4; i++ {
defer fmt.Print(i)
}
}
在循环中,依次定义了四个defer代码块。结合规则一,我们可以明确得知每个defer代码块应该输出什么值。 安装先进后出的原则,我们可以看到依次输出了3210.
规则三 defer可以读取有名返回值
先看下面的代码:
func c() (i int) {
defer func() { i++ }()
return 1
}
输出结果是12. 在开头的时候,我们说过defer是在return调用之后才执行的。 这里需要明确的是defer代码块的作用域仍然在函数之内,结合上面的函数也就是说,defer的作用域仍然在c函数之内。因此defer仍然可以读取c函数内的变量(如果无法读取函数内变量,那又如何进行变量清除呢....)。
当执行return 1 之后,i的值就是1. 此时此刻,defer代码块开始执行,对i进行自增操作。 因此输出2.
掌握了defer以上三条使用规则,那么当我们遇到defer代码块时,就可以明确得知defer的预期结果。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。
# golang
# defer
# 顺序
# return
# GO语言延迟函数defer用法分析
# 总结Go语言中defer的使用和注意要点
# Golang巧用defer进行错误处理的方法
# Go语言中的延迟函数defer示例详解
# 聊聊golang中多个defer的执行顺序
# GO语言Defer用法实例分析
# Go使用defer函数要注意的几个点
# golang中defer的基本使用教程
# 的是
# 会在
# 这段
# 我们可以
# 就会
# 说过
# 可以看到
# 三条
# 之内
# 一个函数
# 是在
# 多个
# 句柄
# 这个问题
# 不清楚
# 这条
# 很简单
# 很重要
# 这种情况
# 时就
相关文章:
中山网站制作网页,中山新生登记系统登记流程?
如何用西部建站助手快速创建专业网站?
c# await 一个已经完成的Task会发生什么
建站之星手机一键生成:多端自适应+小程序开发快速建站指南
如何自定义建站之星模板颜色并下载新样式?
如何确保FTP站点访问权限与数据传输安全?
制作网站的基本流程,设计网站的软件是什么?
昆明高端网站制作公司,昆明公租房申请网上登录入口?
如何制作新型网站程序文件,新型止水鱼鳞网要拆除吗?
安徽网站建设与外贸建站服务专业定制方案
成都网站制作报价公司,成都工业用气开户费用?
如何彻底删除建站之星生成的Banner?
,网页ppt怎么弄成自己的ppt?
javascript中的try catch异常捕获机制用法分析
nginx修改上传文件大小限制的方法
实现虚拟支付需哪些建站技术支撑?
一键制作网站软件下载安装,一键自动采集网页文档制作步骤?
制作宣传网站的软件,小红书可以宣传网站吗?
建站主机功能解析:服务器选择与快速搭建指南
建站之星与建站宝盒如何选择最佳方案?
建站主机空间推荐 高性价比配置与快速部署方案解析
如何在香港服务器上快速搭建免备案网站?
如何在Windows环境下新建FTP站点并设置权限?
平台云上自助建站如何快速打造专业网站?
网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?
linux top下的 minerd 木马清除方法
招商网站制作流程,网站招商广告语?
制作网站的网址是什么,请问后缀为.com和.com.cn还有.cn的这三种网站是分别是什么类型的网站?
制作企业网站建设方案,怎样建设一个公司网站?
红河网站制作公司,红河事业单位身份证如何上传?
如何选择长沙网站建站模板?H5响应式与品牌定制哪个更优?
专业公司网站制作公司,用什么语言做企业网站比较好?
免费公司网站制作软件,如何申请免费主页空间做自己的网站?
如何通过可视化优化提升建站效果?
建站之星后台搭建步骤解析:模板选择与产品管理实操指南
公司网站制作价格怎么算,公司办个官网需要多少钱?
建站VPS能否同时实现高效与安全翻墙?
高性能网站服务器配置指南:安全稳定与高效建站核心方案
网站规划与制作是什么,电子商务网站系统规划的内容及步骤是什么?
如何续费美橙建站之星域名及服务?
建站之星后台密码如何安全设置与找回?
建站之星备案是否影响网站上线时间?
网站企业制作流程,用什么语言做企业网站比较好?
如何在Golang中指定模块版本_使用go.mod控制版本号
香港服务器部署网站为何提示未备案?
网站插件制作软件免费下载,网页视频怎么下到本地插件?
全景视频制作网站有哪些,全景图怎么做成网页?
常州自助建站工具推荐:低成本搭建与模板选择技巧
青浦网站制作公司有哪些,苹果官网发货地是哪里?
开源网站制作软件,开源网站什么意思?
*请认真填写需求信息,我们会在24小时内与您取得联系。