详解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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go操作Kafka和Etcd方法详解

    Go操作Kafka和Etcd方法详解

    这篇文章主要为大家介绍了Go操作Kafka和Etcd方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • Golang 实现超大文件读取的两种方法

    Golang 实现超大文件读取的两种方法

    这篇文章主要介绍了Golang 实现超大文件读取的两种方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • Go语言中函数的使用方法详解

    Go语言中函数的使用方法详解

    这篇文章主要为大家详细介绍了Go语言中函数的使用方法的相关资料,文中的示例代码讲解详细,对我们学习Go语言有一定的帮助,感兴趣的可以了解一下
    2023-04-04
  • 使用go求幂的几种方法小结

    使用go求幂的几种方法小结

    这篇文章主要介绍了使用go求幂的几种方法小结,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • go panic时如何让函数返回数据?

    go panic时如何让函数返回数据?

    今天小编就为大家分享一篇关于go panic时如何让函数返回数据?,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-04-04
  • Golang中NetPoll机制的实现

    Golang中NetPoll机制的实现

    本文主要介绍了Golang中NetPoll机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-12-12
  • 5个可以在Golang中优化代码以提高性能的技巧分享

    5个可以在Golang中优化代码以提高性能的技巧分享

    作为一名软件工程师,确保你的代码高效且性能良好是非常重要的。本文主要和大家分享5个可以在Golang中优化代码以提高性能的技巧,希望对大家有所帮助
    2023-03-03
  • go语言实战之实现比特币地址校验步骤

    go语言实战之实现比特币地址校验步骤

    这篇文章主要介绍了go语言实战之实现比特币地址校验步骤,利用生产的随机数采用椭圆加密算法生成公钥,具体步骤实例代码请参考下本文
    2021-05-05
  • Golang 使用事务的简单实践

    Golang 使用事务的简单实践

    事务是保证数据一致性的重要手段,在Golang项目中,我们可以通过事务管理器或GORM的来简化事务的使用,本文就来详细的介绍一下Golang 使用事务的实现示例,感兴趣的可以了解一下
    2025-11-11
  • golang net.url标准库的具体使用

    golang net.url标准库的具体使用

    本文主要介绍了golang net.url标准库的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-06-06

最新评论