设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间01 现在时间01 缓存数据 当你走完一段之后回头看,你会发现,那些真正能被记得的事真的是没有多少,真正无法忘记的人屈指可数,真正有趣的日子不过是那么一些,而真正需要害怕的也是寥寥无几。

当你走完一段之后回头看,你会发现,那些真正能被记得的事真的是没有多少,真正无法忘记的人屈指可数,真正有趣的日子不过是那么一些,而真正需要害怕的也是寥寥无几。

查看: 1786|回复: 2

一文详解go的defer和return的执行顺序

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:203
  • 打卡月天数:0
  • 打卡总奖励:3044
  • 最近打卡:2023-08-27 04:10:06
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
377
主题
355
精华
0
金钱
4156
积分
762
注册时间
2022-12-27
最后登录
2025-8-28

发表于 2024-7-13 18:44:58 | 显示全部楼层 |阅读模式
目录


  • 详解go的defer和return的执行顺序

    • defer和return的相互影响


详解go的defer和return的执行顺序

go的defer和return是golang中的两个关键字,return用于返回函数的返回值,也可以参与一定的流程控制,比如下面代码,return短路了后面的输出
  1. package main

  2. import "fmt"

  3. // defer 和 return的详解
  4. func main() {
  5.         foo(2)
  6.         foo(1)
  7. }
  8. func foo(i int) {
  9.         fmt.Println(i)
  10.         if i == 1 {
  11.                 return
  12.         }
  13.         fmt.Println(i + 1)
  14. }
复制代码
结果:
  1. 231
复制代码
第一次输出完整的输出了i和i+1,第二次输出被短路,只输出了1
defer是golang中的延迟调用,经常用于文件流的关闭,锁的解锁操作,defer后面的操作会在当前函数或者goroutine结束之后进行调用
  1. package main

  2. import "fmt"

  3. // defer 和 return的详解
  4. func main() {
  5.         foo()
  6. }
  7. func foo() {
  8.         defer fmt.Println("println defer")
  9.         fmt.Println("println foo")
  10. }

  11. 输出:
  12. println foo
  13. println defer
复制代码
defer自身有一些特性,比如defer和defer之间的执行顺序是先进后出,先defer的最后执行,分析下面代码:
  1. package main

  2. import "fmt"

  3. // defer 和 return的详解
  4. func main() {
  5.         foo()
  6. }
  7. func foo() {
  8.         defer fmt.Println("floor 3")
  9.         defer fmt.Println("floor 2")
  10.         fmt.Println("floor 1")
  11. }

  12. 输出:
  13. floor 1
  14. floor 2
  15. floor 3
复制代码
根据这一特性,如果我们defer调用的代码中存在panic 的可能性,为了保证系统的运行,我们应该在前面recover而不是后面
  1. ackage main

  2. import "fmt"

  3. // defer 和 return的详解
  4. func main() {
  5.         foo()
  6. }
  7. func foo() {
  8.         defer func() {
  9.                 panic("panic test")
  10.         }()
  11.         defer func() {
  12.                 if err := recover(); err != nil {
  13.                         fmt.Println("catch panic:", err)
  14.                 }
  15.         }()
  16. }

  17. 输出:
  18. panic: panic test
复制代码
  1. package main

  2. import "fmt"

  3. // defer 和 return的详解
  4. func main() {
  5.         foo()
  6. }
  7. func foo() {
  8.         defer func() {
  9.                 if err := recover(); err != nil {
  10.                         fmt.Println("catch panic:", err)
  11.                 }
  12.         }()
  13.         defer func() {
  14.                 panic("panic test")
  15.         }()
  16. }
  17. 输出:
  18. catch panic: panic test
复制代码
defer和return的相互影响

defer和return的相互影响,主要是在返回值上表现,考虑下面代码,输出应该是什么:
  1. import "fmt"

  2. // defer 和 return的详解
  3. func main() {
  4.         fmt.Println(foo1())
  5.         fmt.Println(foo2())
  6.         fmt.Println(foo3())
  7. }
  8. func foo1() int {
  9.         i := 1
  10.         defer func() { i++ }()
  11.         return i
  12. }
  13. func foo2() (i int) {
  14.         i = 1
  15.         defer func() { i++ }()
  16.         return i
  17. }
  18. func foo3() (i int) {
  19.         defer func() { i++ }()
  20.         return 1
  21. }
复制代码
输出:
  1. 122
复制代码
导致上面情况的原因是
  1. foo1
复制代码
函数中,
  1. defer
复制代码
语句中的闭包会在函数返回后执行,但是此时返回值已经确定为
  1. 1
复制代码
,所以最终返回
  1. 1
复制代码

  1. foo2
复制代码
函数中,使用了命名返回值
  1. i
复制代码
  1. defer
复制代码
语句中的闭包修改的是这个命名返回值,所以返回
  1. 2
复制代码

  1. foo3
复制代码
函数中,同样使用了命名返回值
  1. i
复制代码
  1. defer
复制代码
语句中的闭包修改了这个命名返回值,并且函数直接返回
  1. 1
复制代码
,但
  1. defer
复制代码
中的修改使得最终返回
  1. 2
复制代码

而return的另一个特性,也会影响return和defer中代码的执行顺序
  1. package main

  2. import "fmt"

  3. // defer 和 return的详解
  4. func main() {
  5.         fmt.Println(foo1())

  6. }
  7. func foo1() int {
  8.         defer func() { fmt.Println("This is defer") }()
  9.         return func() int {
  10.                 fmt.Println("This is return")
  11.                 return 1
  12.         }()
  13. }

  14. 输出:
  15. This is return
  16. This is defer
  17. 1
复制代码
导致上面输出的原因是,return是非原子性的,defer会在return返回值之前执行,但return中的语句,会被全部执行,直到return锚定了某个值或者命名返回值,然后执行defer语句,最后返回return锚定的这个值
到此这篇关于一文详解go的defer和return的执行顺序的文章就介绍到这了,更多相关go defer和return执行顺序内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

  • 打卡等级:无名新人
  • 打卡总天数:1
  • 打卡月天数:0
  • 打卡总奖励:5
  • 最近打卡:2024-06-10 13:02:53
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
17
积分
4
注册时间
2024-1-11
最后登录
2024-6-10

发表于 2025-3-16 12:40:17 | 显示全部楼层
路过,支持一下
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

  • 打卡等级:无名新人
  • 打卡总天数:2
  • 打卡月天数:0
  • 打卡总奖励:31
  • 最近打卡:2025-03-25 18:12:34
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
44
积分
6
注册时间
2023-7-18
最后登录
2025-3-25

发表于 2025-10-16 07:36:37 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表