首先,先了解一下 return 返回值的运行机制:return 并非原子操作,共分为 赋值、返回值 两步操作。
其次,defer 的执行顺序是先进后出 FILO,也就是先执行最后一个 defer,最后执行第一个 defer。
defer、return、返回值三者的执行是:
- return 最先执行,先将结果写入返回值中(即赋值)
- 接着 defer 开始执行一些收尾工作
- 最后函数携带当前返回值退出(即返回值)。
只要理解这个顺序,剩下的就很好理解了,下面举例说明一下:
不带命名的返回值
func f1() int {
i := 1
defer func() {
i++
}()
return i
}
f1() //1
步骤如下:
- 因为返回值没有命名, 所以返回值会默认指定一个名字, 比如叫
j
, 于是在return i
时,j
被赋值为 1 - 之后执行 defer 操作,
i
变为 2, 但是j
并没有被赋值, 还是 1 - 最后函数返回
j
, 也就是 1
带命名的返回值
带命名的返回值情况稍微复杂一些, 但是按照步骤来还是很好理解
func f2() (i int) {
i = 1
defer func() {
i++
}()
return i
}
f2() //2
步骤如下:
- 因为返回值有命名, 并且是同一个变量, 不需要赋值
- 之后执行 defer 操作,
i
变为 2, 于是返回值也变成了 2 - 最后函数返回
i
, 也就是 2
func f3() (i int) {
j := 1
defer func() {
j++
}()
return j
}
func f4() (i int) {
j := 1
defer func() {
i++
}()
return j
}
f3() //1
f4() //2
f3()
这个情况和不带命名的返回值原理是一样的, 不再赘述
f4()
步骤如下:
- 返回值有命名, 但是不同变量, 所以发生赋值操作
- 之后执行 defer 操作,
i
变为 2, 于是返回值也变成了 2 - 最后函数返回
i
, 也就是 2
func f5() (r int) {
defer func() {
r = r + 5
}()
return 1
}
func f6() (r int) {
defer func(r int) {
r = r + 5
}(r)
return 1
}
f5() //6
f6() //1
f5()
比较好理解,就是普通情况
f6()
是修改的是闭包内的变量, 正好这个变量也叫 r
而已, 并没有修改返回值
暂时想到这些情况, 想到再补充!