go语言defer语句与函数返回值:详解一个易混淆的案例
本文分析一个Go语言中defer语句与函数返回值的典型案例,解释为什么修改defer中返回值的副本不会改变最终结果,以及如何正确修改代码以达到预期效果。
以下代码片段展示了一个常见的误区:
func f3() (r int) { defer func(r int) { r = r + 5 }(r) return 1 }
f3函数返回一个整数r。defer语句中的匿名函数在f3函数返回前执行。关键在于,匿名函数的参数r是f3函数返回值r的副本,而非引用。
当执行return 1时,r的值被设置为1。随后,defer语句执行匿名函数。然而,修改匿名函数参数r(副本)的值,并不会影响f3函数返回值r。因此,f3最终返回1,而非预期的6。
为了得到预期结果(此处应为6,而非5),我们需要避免修改副本。正确的代码如下:
func f3() (r int) { defer func(t int) { r = t + 5 }(r) return 1 }
在这个修正版本中,匿名函数的参数t仍然是r的副本,但我们直接将t + 5的结果赋值给f3函数的返回值r,从而修改了f3函数的返回值。return 1语句仍然存在,但最终返回的是r的最终值。
另一个更简洁的正确版本:
func f3() (r int) { r = 1 defer func() { r += 5 }() return }
此版本直接在defer中修改r,避免了参数传递的副本问题,最终返回6。
总结:Go语言中defer语句执行时,其参数是函数返回值的副本。直接在defer中修改副本并不会影响函数的返回值。要修改返回值,需要在defer中直接操作函数的返回值本身。 理解这一点对于编写正确高效的Go代码至关重要。