golang defer和引用

观察如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, playground")
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
// Output: 4 3 2 1 0
}
fmt.Printf("\n")
for i := 0; i < 5; i++ {
defer func(){ fmt.Printf("%d ", i) } ()
// Output: 5 5 5 5 5
//可以把golang中的闭包对于变量的访问使用当做引用来理解,而defer是把后面的语句放入堆栈中最后才进行执行,所以当最终执行的时候输出的是变量i而,变量i此时已经变成5了:)所以会输出5次
}
}
/*
// 方法1: 每次循环构造一个临时变量 i
for i := 0; i < 5; i++ {
i := i
defer func(){ fmt.Printf("%d ", i) } ()
// Output: 4 3 2 1 0
}
// 方法2: 通过函数参数传参
for i := 0; i < 5; i++ {
defer func(i int){ fmt.Printf("%d ", i) } (i)
// Output: 4 3 2 1 0
}
*/
1
2
3
4
5
> Hello, playground
>
> 5 5 5 5 5 4 3 2 1 0
> Program exited.
>

知识点

  1. defer后续的语句是放入堆栈中在函数return之前会进行执行,并且是先入后出
  2. golang中闭包中对于变量的访问相当于是引用

golang中函数传递都是使用的传值方式进行的,之所以会有函数可以修改map、slice内部值的原因是由于数据结构在内存中的使用包含了指针,每一个slice的元素会包含一个value、count、capacity,value类似于指针,所以使用slice[0]=1是会修改他的第一个元素,从这一方面来说golang还是类C的:)