golang中defer的小坑

我们都知道,defer往往在函数的最后执行,遵循先进后出 原则,在return函数写入返回值后执行,而且传入的形参会立即读入,后续修改对其无影响

Go 函数返回过程完整流程

当一个函数执行到 return 语句时,执行顺序是

  1. 计算 return 后的表达式(如果有的话),将结果赋值给返回值;
  2. 执行所有的 defer 语句(按照后进先出 LIFO 的顺序);
  3. 函数真正返回(携带返回值)

下面来看这三个案例

go 复制代码
package main
​
import "fmt"
​
func Func1() int {
    a := 0
    defer func() {
        a++
    }()
    return a
}
​
func Func2() (a int) {
    a = 0
    defer func() {
        a++
    }()
    return
}
​
func Func3() *int {
    a := new(int)
    *a = 0
    defer func() {
        *a++
    }()
    return a
}
​
func main() {
    fmt.Println(Func1())
    fmt.Println(Func2())
    fmt.Println(*Func3())
}

输出结果为

复制代码
0 1 1

案例分析

这三个究竟有什么区别呢?

案例一:

  1. 首先,我们获得a的值0,然后会重新赋值一份给临时的返回槽(slot)当中
  2. 然后,调用defer,修改局部变量a为1,但是a已被copy一份到返回槽,所以重新赋值没有用
  3. 返回0

案例二:

  1. 首先,我们获得a的值0,然后会重新赋值一份给临时的返回槽(slot)当中
  2. 然后defer修改了引用类型a的值
  3. 返回1

案例三:

与案例一相似,但是传递的是指针,能修改地址中存储的值,所以返回的是1

相关推荐
IronixPay5 分钟前
Telegram Bot 接入 USDT 支付完整教程
后端
IronixPay8 分钟前
Next.js + USDT:15 分钟给你的 SaaS 加上加密货币支付
后端
董员外26 分钟前
LangChain.js 快速上手指南:Tool的使用,给大模型安上了双手
前端·javascript·后端
会员源码网1 小时前
使用`mysql_*`废弃函数(PHP7+完全移除,导致代码无法运行)
后端·算法
洛森唛2 小时前
ElasticSearch查询语句Query String详解:从入门到精通
后端·elasticsearch
用户8307196840822 小时前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
小兔崽子去哪了2 小时前
Java 自动化部署
java·后端
Selicens2 小时前
git批量删除本地多余分支
前端·git·后端
哈密瓜的眉毛美2 小时前
Java 基础补充:零基础学Java | Scanner 类详解
后端
ma_king2 小时前
入门 java 和 数据库
java·数据库·后端