• defer面试题,你能答对几题?


    以下三道题都是defer关键字相关知识,首先在不运行代码的情况下给出返回值。

    原文链接

    题目

    题目1

    func f1() (result int) {
        defer func() {
            result++
        }()
        return 0
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    题目2

    func f2() (r int) {
         t := 5
         defer func() {
           t = t + 5
         }()
         return t
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    题目3

    func f3() (r int) {
        defer func(r int) {
              r = r + 5
        }(r)
        return 1
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    答案

    第一题:输出结果为1

    第二题:输出结果为5

    第三题:输出结果为1

    看一下你答对了几题,是不是和你心中所想不一样?

    接下来详细去分析在go语言中defer关键字和return关键字的执行顺序以及上面的答案为什么是这样。

    defer

    defer是go语言里面提供的关键字,用于声明一个延迟函数,一般用于资源的释放,例如文件资源和网络连接等,标记了defer的语句一般在return语句之前执行,如果有多个defer语句,则遵循栈的调用规则,越后面的语句越先执行。

    代码示例:

    f,err := os.Open(filename)
    if err != nil {
    		log.Println("open file error: ", err)
    }
    defer f.Close()
    
    • 1
    • 2
    • 3
    • 4
    • 5

    上面简单概括了defer的执行顺序和机制,但为什么前面三道题的答案和我们想的都不一样呢?

    defer在return之前执行这个肯定的,在官方文档中也有说到,那么可能存在问题的就是return语句,这也是最重要的一点,return语句不是原子操作!

    这是什么意思呢?就是说return语句实际上是分为两步完成的,第一步给返回值赋值,第二步返回值。那么defer语句就可能在赋值和返回值之间修改返回值,使最终的函数返回值与你想象的不一致。

    可以把return拆分来写,就会更加清楚的明白这个原理。

    func f1() (result int) {
    	return = 0
    	defer ...
    	return result
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    答案解析

    我们可以把三个题目的代码分别拆开来写,就能够明白为什么。

    题目1

    func f1() (result int) {
         result = 0    // 先给result赋值
         func() {      // defer插入到赋值和返回之间,修改了result的值
             result++
         }()
         return        // 最后返回的就是被修改了的值
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    题目2

    func f2() (result int) {
         tmp := 5
         result = tmp    // 赋值
         func() {        // defer被插入到赋值与返回之间执行,但是并没有改动到result
             tmp = tmp + 5
         }
         return          // 最后返回的return就是5
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    题目3

    func f3() (result int) {
         result = 1                // 给返回值赋值
         func(result int) {        // 这里改的result是传值传进去的result,不会改变前面赋值的result
              result = result + 5
         }(result)
         return                    // 最后return的是1
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    结论

    defer确实是在return前面调用的,但是由于return并不是一个原子操作,defer语句的执行是在return的赋值和返回之间,所以如果defer语句涉及到了修改返回值,那么就会改变最后return的值。

  • 相关阅读:
    Spring MVC应该怎么学?这份教程带你快速入门,深入剖析源码!
    我的奋斗:我在外企那些年(二)
    卷起来了 手把手带你写一个中高级程序员必会的分布式RPC框架
    【cesium】3D Tileset 模型加载并与模型树关联
    SpringBoot对于SpringMVC的支持
    windows什么录屏软件好用,windows屏幕录制软件
    卡尔曼滤波之最优状态估计和最优状态估计算法
    【小样本实体识别】Few-NERD——基于N-way K-shot的实体识别数据集和方法介绍
    分支路径图调度框架在vivo效果广告业务的落地实践
    vuejs - - - - - 使用code编辑器codemirror
  • 原文地址:https://blog.csdn.net/qq_41286145/article/details/136764990