当前位置: 首页 > article >正文

golang中return和defer的执行顺序的一道题

在Go语言中,return语句和defer语句的执行顺序是一个很重要的概念。让我们详细探讨一下:

  1. 基本执行顺序:

    • 当一个函数执行到return语句时,Go会先计算返回值。
    • 然后,在函数真正返回之前,所有的defer语句会按照后进先出(LIFO)的顺序执行。
    • 最后,函数返回。
  2. 详细过程:

    a. 遇到return语句:

    • 计算返回值
    • 如果是命名返回值,将结果保存到返回变量中
    • 如果不是命名返回值,将结果保存到一个临时区域

    b. 执行defer语句:

    • 按照defer的定义顺序的倒序执行所有defer语句
    • 如果defer中修改了命名返回值,改动会被保留
    • 如果不是命名返回值,defer中的修改不会影响返回值

    c. 函数返回:

    • 返回之前计算的值(可能被defer修改,如果是命名返回值的话)
  3. 示例:

func example() (result int) {
    defer func() {
        result++
    }()
    return 0
}

在这个例子中:

  1. return 0 将 0 赋值给 result

  2. defer 函数执行,将 result 增加到 1

  3. 函数返回 1

  4. 注意事项:

    • defer语句在return语句之后执行,但在函数返回之前执行。
    • 多个defer语句会以栈的方式执行(后进先出)。
    • defer可以读取并修改命名返回值,但不能修改未命名的返回值。
  5. 最佳实践:

    • 理解defer和return的执行顺序可以帮助避免一些微妙的bug。
    • 在使用defer时,尤其是在修改返回值时,要格外小心。
    • 如果需要在defer中修改返回值,使用命名返回值。

理解这些概念对于编写可靠的Go代码非常重要,尤其是在处理资源清理和错误处理时。

接下来我们看下面两个函数,看起来很相似,但它们的返回值是不同的。让我们逐个分析:

  1. 第一个函数:
func myFunction() (x int) {
    x = 1
    defer func() {
        x++
    }()
    return x
}

返回值: 2

  1. 第二个函数:
func myFunction() int {
    x := 1
    defer func() {
        x++
    }()
    return x
}

返回值: 1

解释为什么会有这种差异:

  1. 第一个函数使用了命名返回值 (x int)。在 Go 中,当使用命名返回值时,return 语句可以是空的(就像这里的 return x),它会自动返回命名的返回值变量。更重要的是,defer 函数可以修改这个命名返回值。

    执行顺序:

    • x 被初始化为 1
    • return x 准备返回 1
    • defer 函数执行,将 x 增加到 2
    • 函数返回 2
  2. 第二个函数没有使用命名返回值。它只是声明了一个局部变量 x。在这种情况下,return x 会立即将 x 的当前值(1)复制到返回值中。defer 函数仍然会执行并增加局部变量 x 的值,但这不会影响已经确定的返回值。

    执行顺序:

    • x 被初始化为 1
    • return x 复制 1 到返回值
    • defer 函数执行,将局部变量 x 增加到 2,但不影响返回值
    • 函数返回 1

这个例子很好地展示了 Go 中命名返回值和 defer 语句的微妙之处。在使用 defer 和返回值时,理解这些细节非常重要,因为它们可能导致意料之外的行为。


http://www.kler.cn/a/288397.html

相关文章:

  • Unity安装后点击登录没反应
  • 蓝队知识浅谈(上)
  • 大数据新视界 -- 大数据大厂之 Impala 存储格式转换:从原理到实践,开启大数据性能优化星际之旅(下)(20/30)
  • Ruby编程语言全景解析:从基础到进阶
  • 软件测试:测试用例详解
  • 向日葵软件Windows系统连接苹果系统(MacOS)的无反应问题解决办法
  • 华为与联发科的专利博弈:技术较量还是市场重塑?
  • 【区块链 + 物联网】斐得坊智慧停车区块链 | FISCO BCOS应用案例
  • 【教程】2024.09.03 Qlib数据加载器以及数据集加载器 Alpha158 Aplha360详细的讲解,以及源码
  • JAVAEE初阶第二节——多线程基础(上)
  • golang关于slice map函数传参的小问题
  • 娱乐小项目-树莓派履带小车
  • 中兴-ZSRV2路由器-任意文件读取
  • arcgisjs4.0 内网部署字体不显示问题处理
  • 【技术详解】Java泛型:全面解析与实战应用(进阶版)
  • sqli-labs靶场通关攻略(六十一关到六十五关)
  • ARM/Linux嵌入式面经(三十):腾讯 C++开发工程师
  • 【Linux学习】Linux开发工具——vim
  • html+css+js网页设计 博物馆 亚历山大美术馆6个页面
  • Flask中的g的作用
  • Linux学习笔记(4)----Debian压力测试方法
  • 日本IT编程语言对比分析-Python /Ruby /C++ /Java
  • 【加密社】马后炮视角来看以太坊二层战略
  • LLM大模型:不要怪大模型回答质量不行了,那是你不会问~
  • 计算机视觉之 SE 注意力模块
  • 微信小程序接入客服功能