
👨💻 关于作者:会编程的土豆
"不是因为看见希望才坚持,而是坚持了才看见希望。"
你好,我是会编程的土豆,一名热爱后端技术的Java学习者。
📚 正在更新中的专栏:
-
《数据结构与算法》😊😊😊
-
《leetcode hot 100》🥰🥰🥰🤩🤩🤩
-
《数据库mysql》
💕作者简介:后端学习者
defer 是 Go 里一个非常"有味道"的关键字。
很多人一开始只会用,但其实不理解执行顺序和坑点,很容易写错代码。
这篇直接帮你彻底搞懂。
一、defer 是什么?
一句话:
defer = 延迟执行,在函数结束前执行
最简单例子
Go
func main() {
fmt.Println("start")
defer fmt.Println("defer")
fmt.Println("end")
}
输出
start
end
defer
核心结论
defer 一定在函数 return 之前执行
二、多个 defer 的执行顺序(重点)
示例
Go
func main() {
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
}
输出
3
2
1
结论
defer 是栈结构(后进先出 LIFO)
👉 类比:
像压栈 → 出栈
三、defer + return(高频考点)
示例
Go
func test() int {
defer fmt.Println("defer")
return 10
}
执行顺序(非常重要)
1. 计算 return 的值
2. 执行 defer
3. 返回
四、经典陷阱:defer 修改返回值
示例1(无效修改)
Go
func test() int {
a := 10
defer func() {
a = 20
}()
return a
}
返回值
10
为什么?
return a 已经把值拷贝走了
示例2(有效修改)
Go
func test() (a int) {
a = 10
defer func() {
a = 20
}()
return
}
返回值
20
关键区别
✔ 命名返回值 → defer 可以修改
✔ 普通返回值 → defer 修改不了
五、defer + 参数(超级容易错)
示例
Go
func main() {
a := 10
defer fmt.Println(a)
a = 20
}
输出
10
原因
defer 在注册时就把参数"拷贝"了
对比:闭包写法
Go
defer func() {
fmt.Println(a)
}()
输出
20
结论
defer参数:立即求值
defer函数:延迟执行
六、defer 的典型应用场景
1. 关闭资源(最重要)
Go
file, _ := os.Open("test.txt")
defer file.Close()
2. 解锁
Go
mu.Lock()
defer mu.Unlock()
3. 计时
Go
start := time.Now()
defer func() {
fmt.Println(time.Since(start))
}()
七、defer 的底层理解(面试加分)
本质
defer = 把函数压入一个栈
执行时机
函数 return 前,按栈顺序执行
八、性能问题(进阶)
早期 Go
defer 较慢
现在(Go 1.20+)
优化后基本可以放心使用
九、常见坑总结(必须记住)
1️⃣ defer 顺序是反的
后写先执行
2️⃣ 参数是立即计算
defer fmt.Println(a) // 立即拷贝
3️⃣ 命名返回值可以被修改
func f() (a int)
4️⃣ defer 不要写在循环里(可能性能问题)
十、一句话总结
defer = 注册一个"收尾操作",在函数退出前按栈顺序执行