前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面试官:听说你精通golang的defer?

面试官:听说你精通golang的defer?

作者头像
后端时光
发布2022-08-19 10:19:13
4941
发布2022-08-19 10:19:13
举报
文章被收录于专栏:后端时光

本篇文章基于 Golang 1.17.2

书接上回,胖虎前几天面试了一个“双休”的公司,但是他并不想去,他觉得他配不上这么优秀的公司,于是又开始了漫长的面试之路。

面试官:“看你简历上面写着精通 Golang, 那我问个简单的问题吧,什么defer”

胖虎:defer语句注册了一个函数调用,这个调用会延迟到defer语句所在的函数执行完毕后执行,所谓执行完毕是指该函数执行了return语句、函数体已执行完最后一条语句或函数所在的协程发生了panic。

胖虎回答问后,心想:“我厉害吧,把defer语句的官方解释都背下来了,作为优质的八股文选手,快给我发offer吧!!老板,走过路过,不要错过”

面试官看着胖虎自己在那演戏,笑而不语。继续问道:“那你说说为什么需要defer吧”

为什么需要defer

胖虎:在写代码的时候,经常会需要申请一些资源,比如数据库连接、mysql事务的提交等。

但是经常忘记释资源,并且释放的地方太多

导致很多重复代码,很容易出现事故。

defer关键字就可以解决此类问题,

在函数运行完毕后,释放响应的资源。

面试官:“那你说下defer常见的应用场景吧”

defer的执行顺序

多个defer出现的时候,它是一个“栈”的关系,也就是先进后出。一个函数中,写在前面的defer会比写在后面的defer调用得晚。

代码语言:javascript
复制
package main
import"fmt"

func main(){
    defer func1()
    defer func2()
    defer func3()
}

func func1(){
    fmt.Println("func1")
}

func func2(){
    fmt.Println("func2")
}

func func3(){
    fmt.Println("func3")
}

执行结果如下:

原因如下

defer与return

代码语言:javascript
复制
package main
import"fmt"

func main(){
    test()
}
func test() string{
    defer fmt.Println("我是defer")
    return testRet()
}

func testRet() string{
    fmt.Println("我是testRet")
    return""
}

执行结果如下:

结论为:return之后的语句先执行,defer后的语句后执行

defer与panic

代码语言:javascript
复制
package main
import "fmt"

func main() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Printf("err信息是:%+v\n", err)
        }
    }()
    panic("我是panic")
}

执行结果如下:

结论为:遇到panic时,遍历本协程的defer链表,并执行defer。在执行defer过程中:遇到recover则停止panic,返回recover处继续往下执行。

defer与os.Exit()

代码语言:javascript
复制
package main
import (
    "fmt"
    "os"
)

func main() {
    defer func() {
        fmt.Printf("我是defer信息")
    }()
    os.Exit(1)
}

执行结果如下:

结论:当发生panic时,defer会被执行,但是当调用os.Exit()方法退出程序时,defer并不会被执行。

defer遇到返回值为命名变量

代码语言:javascript
复制
package main

import (
    "fmt"
)

func main() {
    fmt.Println(test())
}

func test() (res string) {
    res = "res"
    defer func() {
        res = "我是defer"
    }()
    return "我是最终结果"
}

最终结果是:

原因:

  1. 11行res变量为"", 12行res值为"res"
  2. 执行return语句将"我是最终结果"赋值给变量res
  3. 执行defer方法,将res 修改为"我是defer"
  4. 最终结果就是“我是defer”

defer遇到返回值为匿名变量

代码语言:javascript
复制
package main

import (
    "fmt"
)

func main() {
    fmt.Println(test())
}

func test() string {
    res := "res"
    defer func() {
        res = "我是defer"
    }()
    return "我是最终结果"
}

执行结果是:

执行步骤:

  1. 11行res变量为"", 12行res值为"res"
  2. 执行return语句将"我是最终结果"赋值给匿名变量
  3. 执行defer方法,将res 修改为"我是defer", 但对匿名变量并没有影响
  4. 最终结果就是“我是最终结果”

总结如下:

胖虎一口气说了这么多,内心想:这次志在必得啊。我明天就能入职,快找我进来吧

面试官:小伙子不错啊,这样吧,在面试你最后一题,你要是能答上来,薪资大胆要,要多少,我们就给多少。

以下代码执行结果是什么?为什么?

代码语言:javascript
复制
package main
import (
    "fmt"
)

func main() {
    test()
    panic("main painc了!")
}

func test() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Printf("err信息是:%+v\n", err)
        }
    }()
}

胖虎:“……”,这题不会啊,眼看煮熟的鸭子飞跑了,胖虎流下没有技术的泪水。

面试官:不着急,看你的确挺厉害的,给你一次场外求助的机会,读者在评论区留言,在评论区选择出认为对的答案,也算面试成功。

胖虎:“有知道的大佬吗?在线等”

福利

我为大家整理了一些学习资料礼包,关注公众号回复指令:【Golang】、【操作系统】、【Linux】、【LeetCode】、【Golang电子书】即可获得相应学习资料!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-03-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 后端时光 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么需要defer
  • defer的执行顺序
  • defer与return
  • defer与panic
  • defer与os.Exit()
  • defer遇到返回值为命名变量
  • defer遇到返回值为匿名变量
  • 福利
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档