V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
Ansen
V2EX  ›  Go 编程语言

这结果为啥会是 6 呢?

  •  
  •   Ansen · 2021-01-07 11:25:53 +08:00 · 3283 次点击
    这是一个创建于 1198 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在 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

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

    如果是匿名返回值,即没有主动声明变量来指代栈中的返回值,那自然是没办法直接修改的。
    因为要使用 defer 修改返回值,所以要使用命名返回值。
    emeab
        11
    emeab  
       2021-01-07 14:37:40 +08:00
    golang 为什么那么喜欢写的那么套娃.
    bruce0
        12
    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
        13
    frozenshadow  
       2021-01-07 17:24:48 +08:00 via Android
    厚颜无耻的贴一下之前写了一半的分析。能理解楼上各位大佬说的 golang 传值和返回值方式,这个问题就很好理解了 https://timelife.me/index.php/archives/163/
    hbolive
        14
    hbolive  
       2021-01-08 09:04:33 +08:00
    好像某些面试官喜欢问这种问题。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2714 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 14:53 · PVG 22:53 · LAX 07:53 · JFK 10:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.