这结果为啥会是 6 呢?

2021-01-07 11:25:53 +08:00
 Ansen

在 Q 群里看到这个问题,小白没想明白

play: https://play.golang.com/p/GB1rSAsoTsz

代码如下:

package main

import (
	"fmt"
)

func f2() (x int) {
	defer func() {
		x++
	}()
	return 5
}

func main() {
	x := f2()
	fmt.Println("x: ",x)
}

运行返回: x: 6

3292 次点击
所在节点    Go 编程语言
14 条回复
KaynW
2021-01-07 11:30:04 +08:00
匿名返回值和命名返回值 defer 处理的不一样
https://my.oschina.net/henrylee2cn/blog/505535
Oktfolio
2021-01-07 11:30:29 +08:00
return 先执行,5 赋值给 x 了,然后又 x++,最终返回的就是 6,好像是这样?
catror
2021-01-07 11:31:12 +08:00
因为先执行 return,再执行 defer
rickiey
2021-01-07 11:34:30 +08:00
return 5 在这可以理解分为两步,1 先赋值 x=5,2 再 return 跳转返回 ,而 defer 在 return 之前,也就是 1 和 2 之间,
rickiey
2021-01-07 11:35:52 +08:00
平时尽量不要给返回值命名,直接返回 int 就行了
Ansen
2021-01-07 11:51:55 +08:00
@rickiey #5 谢谢提醒
CEBBCAT
2021-01-07 13:19:20 +08:00
https://play.golang.com/p/2Q1TTx7WNkn
defer 部分对 x 有了改动
---
我平常挺习惯给返回值命名的
TypeErrorNone
2021-01-07 14:19:03 +08:00
HiShan
2021-01-07 14:24:58 +08:00
这个变量命名让人迷惑
RedBlackTree
2021-01-07 14:26:29 +08:00
因为 return 5 包括三步:
1.给栈里的返回值赋值,即 x = 5 ;
2.执行 defer 注册的 func,x++;
3.return

如果是匿名返回值,即没有主动声明变量来指代栈中的返回值,那自然是没办法直接修改的。
因为要使用 defer 修改返回值,所以要使用命名返回值。
emeab
2021-01-07 14:37:40 +08:00
golang 为什么那么喜欢写的那么套娃.
bruce0
2021-01-07 14:49:57 +08:00
这要从 go 的函数调用说起了

C/C++ 等都是用寄存器实现函数返回值的,go 因为支持多返回值, 所以 go 使用调用者的栈空间作为函数的返回值
也就是说
f2 中的 x 实际上是 main 函数中的地址, return5 时,相当于给 x 赋值 5, 在 defer 中 又 x++ 所以 x 就是 6
frozenshadow
2021-01-07 17:24:48 +08:00
厚颜无耻的贴一下之前写了一半的分析。能理解楼上各位大佬说的 golang 传值和返回值方式,这个问题就很好理解了 https://timelife.me/index.php/archives/163/
hbolive
2021-01-08 09:04:33 +08:00
好像某些面试官喜欢问这种问题。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/742480

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX