【Golang】Go语言中defer与return的精妙交织:探索延迟执行与返回顺序的微妙关系

【Golang】Go语言中defer与return的精妙交织:探索延迟执行与返回顺序的微妙关系

大家好 我是寸铁👊
总结了一篇defer 和 return 返回值 的执行顺序探讨的文章✨
喜欢的小伙伴可以点点关注 💝

在这里插入图片描述


前言

在Go语言中,defer return是两个非常重要的关键字,它们在函数执行过程中起着至关重要的作用。defer 用于延迟执行一个函数调用,通常用于在函数执行结束后进行一些清理工作或资源释放操作。而return则用于从函数中返回结果并终止函数的执行。在Go语言中,defer 语句的执行时机和返回值的处理方式涉及到一些微妙的规则,特别是在 defer 和 return 同时出现时,其执行顺序可能会引发一些混淆和困惑
本文将深入探讨Go语言中 deferreturn的执行顺序,并解释它们之间的关系。我们将详细讨论在不同情况下,deferreturn 的执行顺序及其影响,以帮助读者更好地理解和使用这两个关键字,从而写出更加健壮、清晰的代码。

defer与return常考点

简述 defer return 返回值 的执行顺序?如果要返回一个 defer 执行后的值, 可以通过哪些方式?


程序1

不返回具体变量

执行顺序:
进入test函数

  1. 先把返回的结果赋值
  2. 执行defer函数
  3. 如果说defer函数中存在打印输出的内容,则先输出defer语句的内容。
    按照指定的顺序输出,后进先出的顺序输出
  4. 再返回到主函数main中,把之前赋值的返回的结果输出来

注意:return的结果是不会受defer函数而影响的,但是假如在defer外return之前进行赋值
则会返回当前更新的值。

demo


func Test() int {a := 1defer func() {fmt.Println("a", a) // a 1 a = 4fmt.Println("2", a) // 2 4}()return a // 1
}
func main() {fmt.Println(Test()) //1}

程序2

返回指定的变量

执行顺序:
进入test函数

  1. 先把返回的结果赋值
  2. 执行defer函数
  3. 如果说defer函数中存在打印输出的内容,则先输出defer函数语句的内容。
    按照指定的顺序输出,后进先出的顺序输出
  4. 再返回到主函数main中,把之前赋值的返回的结果输出来

注意:函数中先对返回的结果进行定义:= 而不是直接赋值=,return的结果是不会受defer函数而影响的,但是假如在defer外 return之前进行赋值 则会返回当前更新的值。如下demo1和demo2


函数内先对返回值定义:=

demo1

func f() (r int) {t := 5defer func() {t = t + 5}()return t
}
func main() {fmt.Println(f())//5
}

验证一下return的结果会不会受到defer函数的影响
根据输出结果,是不会受到影响的!

demo2

func f() (r int) {t := 5defer func() {t = t + 5t = 12}()t = 20return t //此时t从5 --> 20
}
func main() {fmt.Println(f())//20
}

再来看这种情况,与上面的demo不同的点在于返回参数result在defer中参与了运算

demo3

func deferFuncReturn() (result int) {i := 5defer func() {result += 5}()return i //这里由于返回的result参与了运算,所以会经过defer处理,返回的结果为10
}

函数说明:

函数拥有一个具名返回值result,函数内部声明一个变量idefer指定一个延迟函数,最后返回变量i。延迟函数中增加result

参考答案:

函数输出10。函数的return语句并不是原子的,实际执行分为设置返回值—>ret,defer语句实际执行在返回前,即拥有defer的函数返回过程是:设置返回值—>执行defer—>ret。所以return语句先把result设置为i的值,即5,defer语句中又把result递增5,所以最终返回10。

小结:
所以,这里的关键点在于具名返回值(也就是返回的参数列表中的变量)是否参与defer 运算,参与运算则返回值会受到defer的处理影响,不参与则与之无关。


函数内没有对返回值进行定义

函数中没有对返回值进行定义(:=) 函数返回值先进行初始化 之后在函数内进行赋值 之后defer函数可以返回经过defer操作后的值

返回值是与defer中的程序有关
demo

package mainimport "fmt"func f() (t int) {t = 5defer func() {t = t + 5}()return t //返回值是与defer中的程序有关 
}
func main() {fmt.Println(f())
}

分析:defer在return之后执行,但是在函数退出之前,defer可以修改返回值。这里是先对返回值赋值为5 之后待返回值赋值后 执行defer函数 对t的值进行修改 之后返回的值t也会被defer函数所修改。


再来看一下这一组demo

返回值是与defer中的程序有关 如果在defer的外面重新给t赋值后 则返回的结果值会随之修改

demo


package mainimport "fmt"func f() (t int) {t = 5defer func() {t = t + 5}()t  = 12return t //返回值是与defer中的程序有关 如果在defer的外面重新给t赋值后 则返回的结果值会随之修改
}
func main() {fmt.Println(f())//17
}

分析:这里先对返回值t进行赋值 此时t为5 此时还没执行defer函数 是在赋值给return 的结果完毕后才执行defer函数 很明显 这里t又被修改为12 此时t的值赋值完毕 开始执行defer函数,对t的值进行修改,此时t = 12 + 5 = 17 返回给主函数 输出17

返回一个defer执行后的值

如果要返回一个 defer 执行后的值, 可以通过那些方式?
见上:函数中没有对返回值进行定义的情况

简述:函数中没有对返回值进行定义(:=) 函数返回值先进行初始化 之后在函数内进行赋值 之后defer函数可以返回经过defer操作后的值


结语

通过本文的讨论,我们更深入地理解了Go语言中 defer 和 return 的执行顺序以及它们之间的关系。defer 语句的延迟执行在函数返回前确保了一些清理工作的完成,而 return 的执行顺序则会受到 defer 的影响,需要注意避免出现意外情况。在编写Go语言程序时,合理使用 defer 和 return 可以使代码更加清晰、简洁,并保证资源的正确释放和程序逻辑的正确执行。希望本文能够帮助读者更好地理解和应用这两个关键字,从而写出高质量的Go语言代码。


看到这里的小伙伴,恭喜你又掌握了一个知识点👊
后续有更新和变动,会在这里统一做更新,大家可以关注一波🙌
希望大家能取得胜利,坚持就是胜利💪
我是寸铁!我们下期再见💕


往期好文💕

保姆级教程

【保姆级教程】Windows11下go-zero的etcd安装与初步使用

【保姆级教程】Windows11安装go-zero代码生成工具goctl、protoc、go-zero

【Go-Zero】手把手带你在goland中创建api文件并设置高亮


报错解决

【Go-Zero】Error: user.api 27:9 syntax error: expected ‘:‘ | ‘IDENT‘ | ‘INT‘, got ‘(‘ 报错解决方案及api路由注意事项

【Go-Zero】Error: only one service expected goctl一键转换生成rpc服务错误解决方案

【Go-Zero】【error】 failed to initialize database, got error Error 1045 (28000):报错解决方案

【Go-Zero】Error 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)报错解决方案

【Go-Zero】type mismatch for field “Auth.AccessSecret“, expect “string“, actual “number“报错解决方案

【Go-Zero】Error: user.api 30:2 syntax error: expected ‘)‘ | ‘KEY‘, got ‘IDENT‘报错解决方案

【Go-Zero】Windows启动rpc服务报错panic:context deadline exceeded解决方案


Go面试向

【Go面试向】defer与time.sleep初探

【Go面试向】defer与return的执行顺序初探

【Go面试向】Go程序的执行顺序

【Go面试向】rune和byte类型的认识与使用

【Go面试向】实现map稳定的有序遍历的方式

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

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

相关文章

二进制文件的膨胀策略和使用 debloat 消除膨胀测试

在恶意软件的分析中有的 Windows 可执行文件(PE 文件)会通过膨胀策略来绕过防病毒一些防病毒的检查,比如上传云进行分析,因为文件太大了所以无法进行一些防病毒分析。一般的可执行文件有很多的膨胀策略,一般简单的膨胀…

NettyのBufferChannelSelector用法

这一篇介绍Buffer&Channel&Selector的常见API使用案例 1、Buffer 1.1、从Buffe中读取/写入 以ByteBuffer为例。Buffer需要和Channel结合使用(在上一篇中提到,通道是数据传输的载体,缓冲区是数据的临时存储区)。 那么如何…

OSFP 1类LSA详解

概述 上图为1类LSA的实际报文结构 , 在开始之前一定需要说明 , 1类LSA是OSPF中最复杂的LSA类型 , 在LSA头部的文章中详细介绍了 LS Type / Link State ID / Adv Router 3种头部字段 , 在1类LSA的主体内容中还存在类似的字段十分的相似 , 很多网络从业者难以理解的点就在于此 , …

orbslam2代码解读(2):tracking跟踪线程

书接上回,mpTracker->GrabImageMonocular(im,timestamp)函数处理过程: 如果图像是彩色图,就转成灰度图如果当前帧是初始化的帧,那么在构建Frame的时候,提取orb特征点数量为正常的两倍(目的就是能够在初…

14. RTCP 协议

RTCP 协议概述 RTCP(Real-time Transport Control Protocol 或 RTP Control Protocol 或简写 RTCP),实时传输控制协议,是实时传输协议(RTP)的一个姐妹协议。 注:RTP 协议和 RTP 控制协议&#…

Postgresql源码(135)生成执行计划——Var的调整set_plan_references

1 总结 set_plan_references主要有两个功能: 拉平:生成拉平后的RTE列表(add_rtes_to_flat_rtable)。调整:调整前每一层计划中varno的引用都是相对于本层RTE的偏移量。放在一个整体计划后,需要指向一个统一…

架构设计-全局异常处理器404、405的问题

java web 项目中经常会遇到异常处理的问题,普遍的做法是使用全局异常处理,这样做有以下几种原因: 集中化处理:全局异常处理允许你在一个集中的地方处理整个应用程序中的异常。这有助于减少代码重复,因为你不必在每个可…

项目方案:社会视频资源整合接入汇聚系统解决方案(五)

目录 一、概述 1.1 应用背景 1.2 总体目标 1.3 设计原则 1.4 设计依据 1.5 术语解释 二、需求分析 2.1 政策分析 2.2 业务分析 2.3 系统需求 三、系统总体设计 3.1设计思路 3.2总体架构 3.3联网技术要求 四、视频整合及汇聚接入 4.1设计概述 4.2社会视频资源分…

QT项目实战: 五子棋小游戏

目录 内容介绍 一.添加头文件 二.画棋盘 1.宏定义 2.棋盘 三.画棋子 四.获取棋子摆放位置 五.判断棋子存在 六.判断胜利 1.变量定义和初始化 2.检查获胜条件 3.游戏结束处理 七.重绘 八.效果展示 九.代码 1.mainwindow.h 2.mainwindow.cpp 3.chessitem.h 4…

【python】在【机器学习】与【数据挖掘】中的应用:从基础到【AI大模型】

目录 💗一、Python在数据挖掘中的应用💕 💖1.1 数据预处理💞 💖1.2 特征工程💕 💗二、Python在机器学习中的应用💕 💖2.1 监督学习💞 💖2.2…

【MySQL】(基础篇七) —— 通配符和正则表达式

通配符和正则表达式 本章介绍什么是通配符、如何使用通配符以及怎样使用LIKE操作符进行通配搜索,以便对数据进行复杂过滤;如何使用正则表达式来更好地控制数据过滤。 目录 通配符和正则表达式LIKE操作符百分号(%)通配符下划线(_)通配符 通配符使用技巧正…

深入理解 C++ 智能指针

文章目录 一、引言二、 原始指针的问题1、原始指针的问题2、智能指针如何解决这些问题 三、智能指针的类型四、std::shared_ptr1、shared_ptr使用2、shared_ptr的使用注意事项3、定制删除器4、shared_ptr的优缺点5、shared_ptr的模拟实现 五、std::unique_ptr1、unique_ptr的使…

SpringSecurity入门(三)

12、密码加密 12.1、不指定具体加密方式,通过DelegatingPasswordEncoder,根据前缀自动选择 PasswordEncoder passwordEncoder PasswordEncoderFactories.createDelegatingPasswordEncoder();12.2、指定具体加密方式 // Create an encoder with streng…

【iOS】UI学习——登陆界面案例、照片墙案例

文章目录 登陆界面案例照片墙案例 登陆界面案例 这里通过一个登陆界面来复习一下前面学习的内容。 先在接口部分定义两个UILabel、两个UITextField、两个UIButton按键&#xff1a; #import <UIKit/UIKit.h>interface ViewController : UIViewController {UILabel* _lb…

2024050501-重学 Java 设计模式《实战命令模式》

重学 Java 设计模式&#xff1a;实战命令模式「模拟高档餐厅八大菜系&#xff0c;小二点单厨师烹饪场景」 一、前言 持之以恒的重要性 初学编程往往都很懵&#xff0c;几乎在学习的过程中会遇到各种各样的问题&#xff0c;哪怕别人那运行好好的代码&#xff0c;但你照着写完…

Python数据分析与机器学习在电子商务推荐系统中的应用

文章目录 &#x1f4d1;引言一、推荐系统的类型二、数据收集与预处理2.1 数据收集2.2 数据预处理 三、基于内容的推荐3.1 特征提取3.2 计算相似度3.3 推荐物品 四、协同过滤推荐4.1 基于用户的协同过滤4.2 基于物品的协同过滤 五、混合推荐与评估推荐系统5.1 结合推荐结果5.2 评…

Qwen2本地部署的实战教程

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

网络安全技术实验一 信息收集和漏洞扫描

一、实验目的和要求 了解信息搜集和漏洞扫描的一般步骤&#xff0c;利用Nmap等工具进行信息搜集并进行综合分析&#xff1b;掌握TCP全连接扫描、TCP SYN扫描的原理,利用Scapy编写网络应用程序&#xff0c;开发端口扫描功能模块&#xff1b;使用漏洞扫描工具发现漏洞并进行渗透测…

8款高效电脑维护与多媒体工具合集!

AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频https://h5.cxyhub.com/?invitationhmeEo7 1. 系统安装利器——WinNTSetup 系统安装利器&#xff0c;目前最好用的系统安装器&#xff0c;Windows系统安装部署工具。支持所…

跟我学,数据结构和组原真不难

我个人认为408中计算机组成原理和数据结构最难 难度排行是计算机组成原理>数据结构>操作系统>计算机网络。 计算机组成原理比较难的原因是&#xff0c;他涉及的硬件的知识比较多&#xff0c;这对于大家来说难度就很高了&#xff0c;特别是对于跨考的同学来说&#x…