前言
- 问题来源指路
- 本文内容主要解释向defer语句中传指针(引用类型),然后修改指针指向的变量的值,这种操作是否会导致defer语句中输出的值发生改变。
- 假设
n := 1 ptr := &n solve(ptr)
,你觉得下面两个例子的输出分别是什么呢?
例1
例2func solve(n *int) { defer fmt.Println(*n) *n++ }
func solve(n *int) { defer solve1(n) *n++ } func solve1(n *int) { fmt.Println(*n) }}
输出结果以及解释
输出结果
输出 | |
---|---|
例1 | 1 |
例2 | 2 |
解释
- 只有defer语句后面的函数及其参数会被压入一个全新的栈中,即只能维持defer语句后面的函数及参数的值的不变。
- 对于样例1来说,输出函数和指针n指向的值(*代表解引用)被压入栈中,此时在外部修改指针n指向的值并不会影响输出函数的结果,因为输出函数的参数是从栈中取出的,而非从指针n指向的地址取出的。
栈帧 |
---|
fmt.Println() |
参数1(*n) |
- 于样例2来说,输出函数和指针n被压入栈中,此时在外部修改指针n指向的值会影响输出函数的结果。因为从栈中取出的solve1的参数是一个指针(地址是指针的值,defer维持了指针指向的地址不变),其指向的值发生了变化,因此会影响输出结果。
栈帧 |
---|
solve1 |
参数1(n) |
结论
- defer语句会开辟一个全新的栈帧,维持后面的函数及参数的值的不变。
- 造成上述误导的根源在于指针的值是一个地址,defer只会维持地址不变,而不会维持地址指向的值不变。