defer那些事儿
defer 的参数求值
package main
import "fmt"
func main() {
for i := 0; i < 3; i++ {
defer fmt.Println(i)
}
}
2
1
0
defer 的调用被加入到一个栈中,按照后进先出(LIFO)的顺序执行。
-
defer 参数的求值时机
在 defer 被声明时,fmt.Println(i) 的参数 i 的值会立即求值并保存下来,与循环结束后变量 i 的最终值无关。
-
执行顺序
文件或资源泄漏
package main
import (
"os"
)
func main() {
file, _ := os.Open("nonexistent.txt") // 假设文件不存在
defer file.Close() // 如果 file 是 nil,程序会崩溃
}
多个 defer 顺序
package main
import "fmt"
func main() {
defer fmt.Println("First")
defer fmt.Println("Second")
defer fmt.Println("Third")
}
确保 defer 的顺序符合需求,或者通过显式控制逻辑避免依赖 defer 顺序。
闭包变量捕获问题
package main
import "fmt"
func main() {
for i := 0; i < 3; i++ {
defer func() { fmt.Println(i) }() // 闭包捕获了循环变量 i
}
}
3
3
3
闭包捕获的是变量 i 的引用,而不是每次循环时的值。循环结束后,i 的值是 3,因此所有 defer 使用的都是这个最终值