详解Go中defer与return的执行顺序

 更新时间:2023年07月24日 10:24:56   作者:nil  
Go defer中改变return的值会生效吗,这就设计到了GO语言中defer与return哪个先执行的问题了,下面小编就通过简单的示例来和大家讲讲吧

示例

直接上代码

func test() int {
   result = 123
   defer func() {
      result = 456
   }()
   return result
}
func main() {
   fmt.Println(test())
}

结果

123

修改之后的代码

func test() (result int) {
   result = 123
   defer func() {
      result = 456
   }()
   return result
}
func main() {
   fmt.Println(test())
}

结果

456

再看下面这个例子

func test() (result int) {
   result = 123
   defer func() {
      fmt.Println("aaa")
      result = 456
   }()
   return func() int {
      fmt.Println("bbb")
      return result
   }()
}
func main() {
   fmt.Println(test())
}

结果

bbb
aaa
456

defer与return哪个先执行

这个问题主要是defer 与return哪个先执行。很容易理解如果一个函数中有多个defer,它是栈的形式保存的,执行的时候先从栈顶执行,即后面定义的defer会先被执行,并且defer是在return执行之后才执行的。

因为defer是在return 执行之后才执行的,所以第三个例子中先打印bbb后打印aaa很好理解。

第二个例子和第三个例子test函数返回456也好理解,因为defer可以改变返回值中定义的变量。虽然return已经返回了,defer还是可以改变它。

第一个例子,defer改变的不是返回值中定义的变量,而是局部变量,这个时候return已经执行了,defer改变局部变量没有用。在defer中改变局部变量的值没有效果。第一个例子return result是值拷贝,即将result的值拷贝一份并返回,因此defer改变result并不会影响返回值。

第二、第三例子中return返回的result不是值拷贝,因为result是在返回值中定义的变量,所以return返回的直接是那个变量,这个时候没有值拷贝

再看看下面这个例子

func test() *int {
   result := 123
   defer func() {
      result = 456
   }()
   return &result
}
func main() {
   fmt.Println(*test())
}

结果

456

这个时候defer改变局部变量result又生效了,这是为什么?是因为return 返回的是局部变量的地址,而不是局部变量的只拷贝。因此在defer中修改局部遍历会影响返回结果。

总结

上面描述可能有点绕,需要亲自实验一下,仔细理解才能真正搞懂。下面总结一下我的理解:

return 返回有2种方式:

值拷贝:将局部变量的值拷贝到返回值上。return 直接返回局部变量的值(不是局部变量的引用)

非值拷贝:即return 返回值的时候没有发生值拷贝,有两种情况:

  • 将返回值中定义的变量返回。
  • 将局部变量的引用返回。

非值拷贝的情况下,defer修改返回值是生效的。

return 的执行其实用两步骤:1.先将return的结果赋值到返回值上;2.再将返回值赋值作为函数的结果赋值给调用者。

defer的执行是在return的两步骤中间执行的。所以return如果发生了值拷贝则defer不会改变返回结果;如果return没有发生值拷贝则defer会改变返回结果。

到此这篇关于详解Go中defer与return的执行顺序的文章就介绍到这了,更多相关Go defer return内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang 负载均衡算法实现示例

    Golang 负载均衡算法实现示例

    在Go语言中,负载均衡算法通常由代理、反向代理或者应用层负载均衡器来实现,在这些实现中,有一些经典的负载均衡算法,跟随本文来一一探究
    2024-01-01
  • Go语言变量的声明实现示例

    Go语言变量的声明实现示例

    本文主要介绍了Go语言变量的声明实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-03-03
  • golang elasticsearch Client的使用详解

    golang elasticsearch Client的使用详解

    这篇文章主要介绍了golang elasticsearch Client的使用详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • 精通Go语言日志记录高效日志管理

    精通Go语言日志记录高效日志管理

    本文将深入探讨 Go 语言中的日志记录,包括 Go 的标准日志库的使用、流行的第三方日志库以及如何在实际项目中实现有效的日志管理
    2023-11-11
  • go 压缩解压zip文件源码示例

    go 压缩解压zip文件源码示例

    这篇文章主要为大家介绍了go压缩及解压zip文件的源码示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • golang基础之waitgroup用法以及使用要点

    golang基础之waitgroup用法以及使用要点

    WaitGroup是Golang并发的两种方式之一,一个是Channel,另一个是WaitGroup,下面这篇文章主要给大家介绍了关于golang基础之waitgroup用法以及使用要点的相关资料,需要的朋友可以参考下
    2023-01-01
  • GO语言实现二维码扫码的示例代码

    GO语言实现二维码扫码的示例代码

    你对二维码扫码的流程有困惑吗,这篇文章就结合笔者自身的开发经验进行分享,让大家熟悉并掌握此功能,感兴趣的小伙伴快跟随小编一起学习一下吧
    2023-06-06
  • Golang中interface是引用类型的原因解析

    Golang中interface是引用类型的原因解析

    在Go语言中,将interface设计为引用类型是为了实现更灵活、更动态的类型系统,这篇文章主要介绍了深度解析Golang中为什么interface是引用类型,需要的朋友可以参考下
    2024-01-01
  • GO语言实现的http抓包分析工具pproxy介绍

    GO语言实现的http抓包分析工具pproxy介绍

    这篇文章主要介绍了GO语言实现的http抓包分析工具pproxy介绍,本文同时对比了Fiddler、Charles等抓包软件,需要的朋友可以参考下
    2015-03-03
  • Go系列教程之反射的用法

    Go系列教程之反射的用法

    这篇文章主要介绍了Go系列教程之反射的用法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01

最新评论