0x00 写在前面
笔者在使用 defer 时发现如果涉及到更改函数返回值之情况,不同的代码写法存在不同的结果,暂列出如下几种情况。
0x01 几种情况
以下方法的返回值都通过调用方打印,并且返回值的打印都晚于方法内部 defer 的打印
type deferSt struct {
num int
}
// 直接传值调用函数的方式
func DeferNormal() int {
var i int = 1
defer fmt.Println(i)
i++
return i
}
--------------------
1
2
--------------------
// 指针调用函数的方式
func DeferPoint() int {
s := make([]int, 2)
defer fmt.Println(s)
s[0] = 2
return s[0]
}
--------------------
[2 0]
2
--------------------
// 匿名函数的方式捕获内部变量
func DeferNormalFunc() int {
var i int = 1
defer func() {
fmt.Println(i)
}()
i++
return i
}
--------------------
2
2
--------------------
// 匿名函数捕获指针变量的方式
func DeferPointFunc() int {
st := &deferSt{}
defer func() {
fmt.Println(st)
}()
st.num = 1
return st.num
}
--------------------
&{1}
1
--------------------
// 匿名函数修改具名返回值的值
func DeferClearName() (ret int) {
ret = 1
defer func() {
ret++
fmt.Println(ret)
}()
return ret
}
--------------------
2
2
--------------------
// 匿名函数修改匿名返回值的值
func DeferUnclearName() int {
var i int = 1
defer func() {
i++
fmt.Println(i)
}()
return i
}
--------------------
2
1
--------------------
// 匿名函数捕获指针变量的方式(引用类型)
func DeferUnclearPoint() int {
st := &deferSt{}
defer func() {
st.num = 1
fmt.Println(st)
}()
return st.num
}
--------------------
&{1}
0
--------------------
从上述几种情况中可以看出,除直接传值调用方法及修改匿名返回值之外,其余返回值都与 defer 中的值一致。
0x02 写在后边
综上,尽量不要在 defer 中修改返回值,如果要使用返回值进行某些操作尽量使用 defer + 匿名函数 的方式进行。