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

关于 Go defer 对匿名返回值和命名返回值的不同行为

  •  
  •   ArianX ·
    arianxx · 2019-05-14 23:16:26 +08:00 · 4044 次点击
    这是一个创建于 2019 天前的主题,其中的信息可能已经有所发展或是发生改变。
    func test1() int {
    	var a int
    
    	defer func() {
    		a++
    	}()
    
    	return a
    }
    
    func test2() (a int) {
    	defer func() {
    		a++
    	}()
    
    	return a
    }
    

    test1 最终返回 0,test2 最终返回 1

    这种令人混淆的行为是一个语言缺陷还是一个 feature ?

    今天面试碰上没答起,潜意识认为这两货没区别😥

    reus
        1
    reus  
       2019-05-14 23:27:58 +08:00
    说明你不知道 defer 是在什么时机执行的,基础不牢。
    面试就是要试出你的真实水平,有人连 abc 都认不全,难道是字母“令人混淆”?难道是字母有“缺陷”?
    ArianX
        2
    ArianX  
    OP
       2019-05-14 23:34:45 +08:00
    @reus #1 好的,golang 设计出这两种差异的意愿是因为要说明我基础不牢固
    FEDT
        3
    FEDT  
       2019-05-14 23:40:23 +08:00 via iPhone
    有答案吗
    zzn
        4
    zzn  
       2019-05-14 23:41:29 +08:00
    似乎并不怎么令人混淆吧?
    blless
        5
    blless  
       2019-05-14 23:42:10 +08:00 via Android
    你这代码有问题吧
    silenceshell
        6
    silenceshell  
       2019-05-14 23:46:59 +08:00   ❤️ 1
    defer 发生在“真正”的 retrun 之前。
    Maboroshii
        7
    Maboroshii  
       2019-05-14 23:51:01 +08:00
    学习了。顺便翻了一下资料
    https://blog.golang.org/defer-panic-and-recover
    > 3.Deferred functions may read and assign to the returning function's named return values.
    ArianX
        8
    ArianX  
    OP
       2019-05-14 23:52:30 +08:00 via Android
    @silenceshell 这是作用机制层面上的吧。我想讨论的是究竟为什么要这样设计,在什么场景会用到
    Zzdex
        9
    Zzdex  
       2019-05-14 23:55:25 +08:00
    @ArianX #8 你看楼上的链接,This is convenient for modifying the error return value of a function;
    便于修改错误的返回值
    victor
        10
    victor  
       2019-05-15 00:02:48 +08:00   ❤️ 1
    ArianX
        11
    ArianX  
    OP
       2019-05-15 00:09:37 +08:00 via Android
    匿名返回值函数里的 defer 也能访问到返回值,也允许写出修改返回值的语句,为什么要设计为修改对最终返回的值无效?为什么不直接设计为不允许修改?利用到这种差异的场景是什么?
    poplar50
        12
    poplar50  
       2019-05-15 00:14:09 +08:00 via Android
    学习了,七楼发的链接我看 go tour 的时候还翻过,但是竟然没注意这个。现在想想,defer 既然被设计用来做一些收尾工作,那么出现这种情况就是为了让 defer 也能够处理函数返回值吧。
    ArianX
        13
    ArianX  
    OP
       2019-05-15 00:18:28 +08:00 via Android
    好吧,突然想到某些场景下可能不需要修改最终返回值,但需要在 defer 里使用返回的值做一些操作,于是允许匿名返回值里的 defer 修改返回值,就能够复用同一个变量。
    ArianX
        14
    ArianX  
    OP
       2019-05-15 00:22:41 +08:00 via Android
    话说我想讨论的是为什么要特别设计出匿名返回值和命名返回值 defer 行为的差异,而不是在 defer 里修改返回值的意图
    catror
        15
    catror  
       2019-05-15 00:31:33 +08:00 via Android   ❤️ 1
    你可以这么理解,返回值其实是关联有一个返回变量的,第一个例子里,因为匿名,defer 函数访问不到返回变量,而变量 a 只是局部变量,修改局部变量自然是影响不到返回变量。
    nuance2ex
        16
    nuance2ex  
       2019-05-15 00:42:26 +08:00 via iPhone   ❤️ 1
    @ArianX

    10 楼,这篇从底层原理说了,刚看了不错。
    gamexg
        17
    gamexg  
       2019-05-15 08:42:21 +08:00 via Android
    如 @catror 所说可以认为返回值也是一个变量。
    test1 里面修改的只是局部变量,并未修改 return 变量。
    test2 才是修改的 return 变量。

    可以返回结构指针试试,和不同变量一样,test1 修改结构成员也会修改返回值了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2534 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 01:49 · PVG 09:49 · LAX 17:49 · JFK 20:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.