Go defer简介

news2025/1/12 11:59:07

思考

开始之前,先考虑下下面的代码的执行结果:

package main
 
import "fmt"
 
func test() int {
	i := 0
	defer func() {
		fmt.Println("defer1")
	}()
	defer func() {
		i += 1
		fmt.Println("defer2")
	}()
	return i
}
 
func main() {
	fmt.Println("return", test())
}

defer介绍

defer 是 Go 编程语言中的一个关键字,用于在函数执行结束后延迟执行指定的函数调用。defer 的使用非常灵活,它通常用于执行一些清理操作、资源释放、日志记录等任务。以下是对 defer 的详细介绍:

1.defer 的语法

  • defer 后面跟随一个函数调用,该函数会在包含 defer 语句的函数执行完毕后被调用。
  • 语法示例:defer someFunction()

2. 执行时机

  • defer 函数调用会在包含 defer 语句的函数返回之前执行,即使在函数中间有 return 语句也是如此。
  • 这确保了 defer 中的操作在函数结束时始终执行,无论函数是正常返回还是出现异常。

3. 多个 defer 语句

  • 一个函数可以包含多个 defer 语句,它们会以后进先出(LIFO)的顺序执行。
  • 这意味着最后一个出现的 defer 语句会最先执行,而最先出现的 defer 语句会最后执行。

4. 常见用途

  • 资源释放defer 常用于关闭文件、释放锁、释放内存等资源管理任务,确保资源在函数结束时得到正确释放。
  • 错误处理defer 可以用于记录错误日志或执行清理操作,以确保即使发生错误,资源也能得到释放。
  • 跟踪代码执行defer 还可以用于记录函数的执行情况,以进行性能分析或跟踪代码路径。

5. 示例

  • 下面是一个使用 defer 的示例,演示了文件的打开和关闭操作:
func readFile(filename string) error {
    file, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer file.Close() // 确保文件在函数返回前关闭
 
    // 文件操作...
 
    return nil
}

6. 注意事项:

  • defer 不仅用于函数的返回,还可以用于方法(类似于面向对象编程中的析构函数)。
  • defer 中的参数会在 defer 语句执行时被求值,因此如果你有多个 defer 语句使用相同的参数,它们会被依次求值。
  • 在某些情况下,要特别小心 defer 中的闭包,以避免出现意外的行为。

defer执行时机

defer 语句中的函数调用会在包含 defer 语句的函数返回之前执行。无论函数是正常返回还是在执行中发生了 panic,defer 中的函数都会按照后进先出(LIFO)的顺序执行。这确保了在函数结束时进行清理和释放资源,以及在函数执行期间处理错误或日志记录等任务。

以下是关于 defer 执行时机的详细解释:

1. 正常返回时的 defer 执行

  • 在函数执行过程中,当遇到 defer 语句时,不会立即执行 defer 中的函数调用,而是将它们压入一个栈中,以便在函数返回时执行。
  • 当函数执行完毕并准备返回时,栈中的 defer 函数调用会按照后进先出的顺序执行,确保最后一个 defer 最先执行。

2. 发生 panic 时的 defer 执行

  • 如果函数在执行中发生 panic(异常),同样会执行 defer 中的函数,然后再传播 panic,这允许在 panic 后执行清理操作。
  • 这可以用来释放资源、记录错误信息、关闭连接等。

下面是一个示例,说明了 defer 的执行时机:

func exampleFunction() {
    defer fmt.Println("Deferred 1")
    defer fmt.Println("Deferred 2")
 
    fmt.Println("Function body")
    panic("Something went wrong")
}
 
func main() {
    exampleFunction()
}

在这个示例中,exampleFunction 包含两个 defer 语句和一个 panic。当 exampleFunction 调用时,它首先打印 "Function body",然后执行 defer 中的函数。在 panic 发生后,defer 语句中的函数会按照后进先出的顺序执行。所以,main 函数的输出将是:

Function body
Deferred 2
Deferred 1
panic: Something went wrong

结束

现在回到最开始的问题,在上面的代码中,test 函数包含两个 defer 语句,以及一个 return 语句。在 main 函数中,我们调用 test 并输出其返回值。让我们来解释每一步并分析输出的结果:

  1. i 初始化为 0
  2. 第一个 defer 语句中的匿名函数只是打印 "defer1",不对 i 进行任何修改。
  3. 第二个 defer 语句中的匿名函数增加了 i 的值,然后打印 "defer2"。

现在,让我们分析 test 函数的执行流程:

  1. i 初始化为 0
  2. 第一个 defer 语句注册的函数(打印 "defer1")会在函数返回之前执行,但它没有影响 i 的值。
  3. 接下来,第二个 defer 语句注册的函数(增加 i 的值并打印 "defer2")也会在函数返回之前执行,但在执行时,i 的值仍然为 0
  4. return i 语句返回 0

因此,test 函数返回 0,但在执行过程中,两个 defer 函数都被执行,按照注册的顺序分别打印 "defer1" 和 "defer2"。

在 main 函数中,我们调用 test 并输出其返回值,因此最终的输出是:

defer2
defer1
return 0

这是因为 defer2 和 defer1 的输出分别在 test 函数调用结束之前执行,而 return 0 的结果在函数返回后被 main 函数输出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1192729.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

筹码穿透率指标选股公式,衡量筹码抛压

在前面的文章中,介绍了博弈K线,它是根据筹码分布的原理结合普通K线的方法绘制出来的。当博弈K线的实体部分比较长的时候,说明当天穿越筹码密集区,有大量的筹码解套。通过引入换手率,可以衡量套牢盘的抛压程度。如果穿越…

酷安官网下载页前端自适应源码

酷安官网下载页前端自适应源码,自己拿走玩玩 站长只打开看了一眼,感觉风格还不错,纯html,自己魔改 转载自 https://www.qnziyw.cn/wysc/qdmb/24470.html

commons-io

概述 commons-io是apache开源基金组织提供的一组有关IO操作的类库,可以提高IO功能开发的效率。 commons-io工具包提供了很多有关io操作的类。有两个主要的类FileUtils, IOUtils。 FileUtils主要有如下方法: 使用commons-io简化io流读写 在项目中创建一个文件夹&…

Java系列之:字符串UTF-8 编码格式转换位 UTF-32 【生僻字截取问题】

文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。 前言 在项目开发中遇到这样一个需求&#x…

看农村供水信息化管理系统如何破解供水难题

你是否曾经想过,能够通过一款数字孪生系统平台,解决农村供水的难题?现在,我们带来了这样一款产品,它将为农村供水带来革命性的改变。 我们的农村供水信息化系统,是一款基于数字孪生技术的供水管理平台。它通…

卫星遥感·格物致知丨卫星遥感的力量——自然灾害监测的太空之眼—洪涝灾害监测

遥感卫星从太空感知地球和获取地球表面的信息,当前有上千颗遥感卫星每天不停的对地表成像,其数据广泛用于地球系统科学研究、资源环境管理、国土安全和自然灾害监测等领域。卫星遥感的优势有监测范围大、不受区域地形限制、重复观测和多种类型数据(感知多…

Unity Mirror学习(二) Command特性使用

Command(命令)特性 1,修饰方法的,当在客户端调用此方法,它将在服务端运行(我的理解:客户端命令服务端做某事;或者说:客户端向服务端发消息,消息方法&#xff…

创新无处不在的便利体验——基于智能视频和语音技术的安防监控系统EasyCVR

随着科技的迅猛发展,基于智能视频和语音技术的EasyCVR智能安防监控系统正以惊人的速度改变我们的生活。EasyCVR通过结合先进的视频分析、人工智能和大数据技术,为用户提供了更加智能、便利的安全保护体验,大大提升了安全性和便利性。本文将介…

Geotrust的企业型通配符SSL证书申请

Geotrust作为世界知名的CA认证机构之一,颁发了各种SSL证书,其签发的数字证书被广泛应用于电子商务、企业间通信、网络安全等领域,SSL数字证书可以验证网络中用户的身份,确保数据的机密性和完整性。今天随SSL盾小编了解如何申请Geo…

OpenAI开发者大会大模型圈开卷AI Agent? 实在智能布局前瞻已下“先手棋”

“平地起惊雷,至今有余音。” 去年的11月,OpenAI发布ChatGPT给科技圈劈下了一道惊雷,引爆了全世界的AI大模型热潮,全球科技巨头公司争先恐后地推出通用大模型,探索产业应用的可能。 短短一年后,北京时间1…

ECharts中rich的使用

ECharts官方rich介绍 label: {// 在文本中,可以对部分文本采用 rich 中定义样式。// 这里需要在文本中使用标记符号:// {styleName|text content text content} 标记样式名。// 注意,换行仍是使用 \n。formatter: [{a|这段文本采用样式a},{b…

Vuex模块概念

一、核心概念 - module 1.目标 掌握核心概念 module 模块的创建 2.问题 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。 这句话的意思是,如果把所有的状态都放在s…

别再跟我说你不理解 @Transactional 为什么会失效了!省流版解读

别再跟我说你不理解 Transactional 原理了!省流版解读 前言user 表初始数据隔离级别:NESTED 案例一隔离级别:NESTED 案例一省流版答案解读隔离级别:NESTED 案例一省流版答案源码入口隔离级别 Propagation.NESTED 省流版源码剖析隔…

Fiddler Everywhere for Mac:一款强大且实用的网络调试工具

Fiddler Everywhere是一款备受Mac用户喜爱的网络调试工具,它具有强大的功能和易用性。作为一款老牌抓包工具,Fiddler Everywhere在Mac平台上拥有广泛的应用场景,无论是Web开发、移动应用开发还是网络调试,它都能提供全面的解决方案…

[论文阅读] CLRerNet: Improving Confidence of Lane Detection with LaneIoU

Abstract 车道标记检测是自动驾驶和驾驶辅助系统的重要组成部分。采用基于行的车道表示的现代深度车道检测方法在车道检测基准测试中表现出色。通过初步的Oracle实验,我们首先拆分了车道表示组件,以确定我们方法的方向。我们的研究表明,现有…

单链表(增删改查)【超详细】

目录 单链表 1.单链表的存储定义 2.结点的创建 3.链表尾插入结点 4.单链表尾删结点 5.单链表头插入结点 6.单链表头删结点 7.查找元素,返回结点 8.在pos结点前插入一个结点 ​编辑 9.在pos结点后插入一个结点 10.删除结点 11.删除pos后面的结点 12.修改…

XOR Construction

思路: 通过题目可以得出结论 b1^b2a1 b2^b3a2 ....... bn-1^bnan-1 所以就可以得出 (b1^b2)^(b2^b3)a1^a2 b1^b3a1^a2 有因为当确定一个数的时候就可以通过异或得到其他所有的数,且题目所求的是一个n-1的全排列 那么求出a的前缀异或和arr之后…

微软surface laptop禁用触摸屏(win10、设备管理器)

参考链接: 在屏幕中启用和禁用触摸屏Windows 设置如下

asp.net校园招聘管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net 校园招聘管理系统是一套完善的web设计管理系统,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库为sqlserver2008,使用c#语言开发 应用技术:asp.net c#s…