golang defer 指针陷阱

先看两个代码:

1
2
3
4
5
6
7
8
9
10
func main() {
t := []int{1, 2, 3}
fmt.Println(&t[0])
for _, i := range t {
defer func(i *int) {
fmt.Println(*i)
}(&i)
}
} // 打印结果:3 3 3

解释:在这个代码里,defer 函数接收的是循环变量 i 的地址。当循环结束后,i 的值为 3。由于 defer 函数会在 main 函数返回前执行,并且此时它们都指向同一个变量 i,所以打印结果为 3 3 3。

1
2
3
4
5
6
7
8
9
10
11
func main() {
t := []int{1, 2, 3}
fmt.Println(&t[0])
for _, i := range t {
x := i
defer func(i *int) {
fmt.Println(*i)
}(&x)
}
} // 打印结果:3 2 1

解释:在这段代码中,每次循环都创建了一个新的局部变量 x,并将 i 的值赋给它。defer 函数接收的是 x 的地址,每个 x 都是独立的,因此 defer 函数会按照逆序打印出 3 2 1。

可以看到,两个代码段唯一的区别就是第二段代码多了一行

1
x := i