1. defer的执行顺序类似于栈,“后进先出”,也就是最先defer的语句最后执行,而最后defer的最先执行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
func main() {
	defer fmt.Println("1")
	defer fmt.Println("2")
	defer fmt.Println("3")
}

//控制台打印
3
2
1

2. defer和return的坑

首先return操作并不是原子操作,他分为2步:一是给返回值赋值,二是return返回值。如果函数中有defer的话,那么defer会被夹杂在2步中间,也就是先给返回值赋值,执行defer,return返回值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
func main() {
	fmt.Println("匿名返回:", a()) //5
	fmt.Println("有名返回:", b()) //6
}

// 匿名返回值
func a() int {
	x := 5
	defer func() {
		x++
	}()
	return x
}

// 有名返回值
func b() (x int) {
	x = 5
	defer func() {
		x++
	}()
	return x
}

使用匿名返回函数,控制台打印的是5,这是执行return x时,首先定义 返回值=x(非同一个变量),然后执行defer x++,最后return返回值,而此时返回值已经=x,x++不会再影响返回值了,所以返回的是5。

使用有名返回时,就指定了返回值=x(同一个变量,内存地址相同),所以x++后,返回的值也++了。

3. defer注册要延迟执行的函数时该函数所有的参数都需要确定其值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
func calc(index string, a, b int) int {
	ret := a + b
	fmt.Println(index, a, b, ret)
	return ret
}

func main() {
	x := 1
	y := 2
	defer calc("AA", x, calc("A", x, y))
	x = 10
	defer calc("BB", x, calc("B", x, y))
	y = 20
}

第一次注册defer calc(“AA”, x, calc(“A”, x, y))时,会执行里面的calc(“A”, x, y),此时x=1,y=2,所以先打印,

1
A 1 2 3

于是defer calc(“AA”, x, calc(“A”, x, y))中的参数被确定,是defer calc(“AA”, 1, 3)

接下来x=10,y没变,仍等于2,执行defer calc(“BB”, x, calc(“B”, x, y)),执行calc(“B”, x, y),打印

1
B 10 2 12

于是defer calc(“BB”, x, calc(“B”, x, y))中的参数被确定,是defer calc(“BB”, 10, 12)

然后按照defer顺序执行,先执行defer calc(“BB”, 10, 12),再执行defer calc(“AA”, 1, 3),所以打印

1
2
BB 10 12 22
AA 1 3 4