defer 的一些用法和猜测

秦川 · · 473 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

以前的代码中,基本上只使用了 defer 作为防御程序 panic 退出的手段,没有仔细考虑过对返回值的影响。今天有同事提到:

如果执行过程中发生 panic,defer函数 recover() != nil的情况下,未命名的返回值的函数会返回什么呢?

之前并没有没有想过这个问题,猜想应该是返回该类型的默认值,试了一下果然如此。

func fooA() float64 {
    defer func() {
        if err := recover(); err != nil {
        }
    }()

    *(*float64)(nil) = 0.1 // panic
    return 1.0
}

fooA() 返回0。

那么如果 defer 函数返回值和上层函数一致,会不会替换掉返回值呢?(会就有鬼了)

func fooB() float64 {
    defer func() float64 {
        if err := recover(); err != nil {
            return 1.1
        } else {
            return 1.2
        }
    }()

    *(*float64)(nil) = 0.1
    return 1.0
}

fooB() 返回0。

事实上,如果要在 defer 中修改函数的返回值,目前我只知道一种办法:使用命名的返回参数:

func fooC() (x float64) {
    defer func() {
        if err := recover(); err != nil {
            x = 1.1
            return
        }
    }()

    *(*float64)(nil) = 0.1
    return 1.0
}

fooC()返回1.1。

官方文档上面的说明:
https://golang.org/ref/spec#Defer_statements

核心的说明我认为是这一句话:

That is, if the surrounding function returns through an explicit return statement, deferred functions are executed after any result parameters are set by that return statement but before the function returns to its caller.

搜索信息的过程中发现这样的一篇文章:一道考察defer与命名返回值的题目

DeferFunc1 和 DeferFunc3 还比较好解释,对于文中的DeferFunc2,强行猜测了一下:

func dfB(i int) int { // return anonymous int,we assume it named `noNameI`。
    t := i // Local var t is assigned to 1.
    defer func() {
        // Here noNameI is 2, t is 1.
        t += i // t is 3, noNameI unchanged.
    }()
    return 2 // noNameI is assigned to 2.
}

dfB() 返回 2,为什么呢?
代码return 2的时候应该是将2赋值给了匿名的返回值变量,因此 defer 函数中的对本地变量的 t 的操作便无关紧要。


有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:秦川

查看原文:defer 的一些用法和猜测

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

473 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传