Go defer简介

思考

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

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 函数输出。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

EasyExcel 导出冻结指定行

导出的实体类 package org.jeecg.modules.eis.test;import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.*; import lombok.Getter; import lombok.Setter; import org.apache.poi.ss.usermodel.HorizontalAlignment;import…

如何在Linux上部署1Panel运维管理面板并远程访问内网进行操作

文章目录 前言1. Linux 安装1Panel2. 安装cpolar内网穿透3. 配置1Panel公网访问地址4. 公网远程访问1Panel管理界面5. 固定1Panel公网地址 前言 1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。高效管理,通过 Web 端轻松管理 Linux 服务器,包括主机监控、…

通义千问, 文心一言, ChatGLM, GPT-4, Llama2, DevOps 能力评测

引言 “克隆 dev 环境到 test 环境,等所有服务运行正常之后,把访问地址告诉我”,“检查所有项目,告诉我有哪些服务不正常,给出异常原因和修复建议”,在过去的工程师生涯中,也曾幻想过能够通过这…

【VUE+ elementUI 实现动态表头渲染】

VUE elementUI 实现动态表头渲染 1、定义 columns(表头数据) 和 dataList(表格数据) data() {return {loading: false,dataList: [{ name: 张三, sex: 男, age: 18 },{ name: 林琳, sex: 女, age: 20 },{ name: 王五, sex: 男, …

已解决:rm: 无法删除“/opt/module/zookeeper-3.4.10/zkData/zookeeper_server.pid“: 权限不够

解决: ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg Stopping zookeeper ... /opt/module/zookeeper-3.4.10/bin/zkServer.sh: 第 182 行:kill: (4149) - 不允许的操作 rm: 无法删除"/opt/module/zooke…

数据结构:串(定义,基本操作,存储结构)

目录 1.串的定义2.串的基本操作3.字符集编码4.串的存储结构1.顺序存储2.链式存储 1.串的定义 串,即字符串( String)是由零个或多个字符组成的有限序列。 一般记为s ‘a1a2……an’ (n ≥0) 其中,S是串名,单引号括起来的字符序列是…

uniApp页面通讯

Uniapp 是一款基于 Vue.js 开发的框架,它可以用来开发多端应用,包括微信小程序、H5、APP 等。在 Uniapp 中,页面通讯分为三种方式:事件总线、Vuex 和 uni.$emit。 事件总线(EventBus):事件总线是…

css设置浏览器表单自动填充时的背景

浏览器自动填充表单内容,会自动设置背景色。对于一般的用户,也许不会觉得有什么,但对于要求比较严格的用户,就会“指手画脚”。这里,我们通过css属性来设置浏览器填充背景的过渡时间,使用户看不到过渡后的背…

小程序版本审核未通过,需在开发者后台「版本管理—提交审核——小程序订单中心path」设置订单中心页path,请设置后再提交代码审核

小程序版本审核未通过,需在开发者后台「版本管理—提交审核——小程序订单中心path」设置订单中心页path,请设置后再提交代码审核 因小程序尚未发布,订单中心不能正常打开查看,请先发布小程序后再提交订单中心PATH申请 初次提交…

IDEA 关闭SpringBoot启动Logo/图标

一、环境 1、SpringBoot 2.6.4 Maven POM格式 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.4</version><relativePath/></parent> 2、IDE…

系列二、Shiro的核心组件

一、核心组件 # 1、UsernamePasswordToken 封装了用户的登录信息&#xff0c;使用用户的登录信息来创建Token # 2、SecurityManager Shiro的核心组件&#xff0c;负责安全认证和授权 # 3、Subject Shiro的一个抽象概念&#xff0c;包含了用户信息 # 4、Realm 开发者自定义的模块…

Day25力扣打卡

打卡记录 寻找旋转排序数组中的最小值&#xff08;二分&#xff09; 链接 由于是旋转排序数组&#xff0c;所以整个数组有两部分是递增的&#xff0c;选取右侧最后元素&#xff0c;即可将整个数组分为大于该元素和小于该元素&#xff0c;碰头地段即为最小值。 class Solutio…

探秘亚马逊云科技海外服务器 | 解析跨境云计算的前沿技术与应用

目录 一、什么是海外服务器 二、不同主流海外云服务器对比 三、海外服务器的创建(亚马逊为例) 四、个人总结 一、什么是海外服务器 亚马逊云科技海外服务器&#xff1a;指的是部署在世界各地的亚马逊数据中心中的服务器设备。这些服务器提供了计算、存储、数据库、网络等各…

最终前端后端小程序还有nginx配置

前端 前端 build 代码及其 放置位置 后端 nginx.conf 配置 user root;worker_processes auto; error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid;events {worker_connections 1024; }http {include /etc/nginx/mime.types;default_type a…

语音控制:基于ESP8266的DIY助手

随着智能家居的兴起&#xff0c;语音控制成为越来越受欢迎的方式。在本篇文章中&#xff0c;我们将向您介绍如何使用ESP8266构建一个基于语音控制的DIY助手。 第一步&#xff1a;硬件准备 在开始之前&#xff0c;您需要准备一些基础硬件&#xff0c;包括ESP8266模块、麦克风模…

【强化学习】结合Python实战深入分析原理

【文末送书】今天推荐一本强化学习领域优质Python算法书籍&#xff0c;揭密ChatGPT关键技术PPO和RLHF。 目录 前言时间旅行和平行宇宙强化学习策略梯度算法代码案例文末送书 前言 时间循环是一类热门的影视题材&#xff0c;其设定常常如下&#xff1a;主人公可以主动或被动的回…

为什么需要Code Review?

1. Code Review 是什么&#xff1f; 代码审查&#xff08;Code Review&#xff09;是软件开发过程中对代码进行系统性检查和评审的一项活动。它是指团队成员之间相互检查彼此编写的代码&#xff0c;以确保代码质量、可读性和符合编码标准等。 2. Code Review 的必要性 ● 提…

[CISCN 2023 初赛]go_session

文章目录 考点代码审计main.goroute.goIndex函数Admin函数Flask函数 解题过程伪造session获取server.py构造payload覆盖server.py命令执行 考点 session伪造&#xff0c;pongo2模板注入&#xff0c;debug模式覆盖源文件 代码审计 main.go package mainimport ("github.c…

小白高效自学-网络安全(黑客技术)

网络安全零基础入门学习路线&规划 初级 1、网络安全理论知识&#xff08;2天&#xff09; 了解行业相关背景&#xff0c;前景&#xff0c;确定发展方向。 学习网络安全相关法律法规。 网络安全运营的概念。 等保简介、等保规定、流程和规范。&#xff08;非常重要&#x…