Go 面试题 014:defer 的变量快照什么情况会失效?

Go编程时光

共 1359字,需浏览 3分钟

 ·

2021-11-11 21:18

大家好,我是明哥。

欢迎大家再次来到  Go 语言面试题库 这个专栏

本篇问题:Go 中闭包的底层原理?

关于 defer 的基本知识点,我在以前的教程中有写过:14. Go语言流程控制:defer 延迟调用

其中有一个知识是 defer 的变量快照,举个简单的例子来说

在下面这段代码中,会先打印出来  18,即使后面 age 已经被改变了,可 defer 中的 age还是 修改之前的 0,这种现象称之为变量快照。

func func1() {
    age := 0
    defer fmt.Println(age) // output: 0

    age = 18
    fmt.Println(age)      // output: 18
}


func main() {
    func1()
}

对于这个输出结果,相信还是挺容易理解的。

接下来,我请大家再看下面这个例子,可以猜猜看会输出什么?

func func1() {
    age := 0
    defer func() {
        fmt.Println(age)
    }()
    age = 18
    return
}

func main() {
    func1()
}

正确的答案是:18, 而不是 0

你肯定会纳闷:不对啊,defer 不是会对变量的值做一个快照吗?答案应该是 0 啊,为什么会是 18?

实际上,仔细观察,可以发现上面的两个例子的区别就在于,一个 defer 后接的是单个表达式,另一个 defer 后接的是一个函数,并且不是普通函数,而是一个匿名的闭包函数。

根据闭包的特性,实际上在闭包函数存的是 age 这个变量的指针(原因可以查看上一篇文章:Go 面试题 013:Go 中闭包的底层原理是?),因而,在 defer 后所修改的值会直接影响到 defer 中的 age 的值。

总结一下:

  1. 若 defer 后接的是单行表达式,那defer 中的 age 只是拷贝了 func1 函数栈中 defer 之前的 age 的值;

  2. 若 defer 后接的是闭包函数,那defer 中的 age 只是存储的是 func1 函数栈中  age 的指针。


是不是很简单呢?

本系列的所有文章,我都开放到 Github 上:https://github.com/iswbm/golang-interview

这个号没有留言功能呢 ,如果文章有写得不对的地方,可以去那里提交 issue 帮我指正。顺便可以帮我点个小 ⭐⭐,在那里我对题库进行了分类整理,方便索引查找。

加油噢,我们下篇见!


文章的最后,插播一个福利

双十一快到了,阿里云也开始搞活动了,刚好我这边可以带大家白嫖阿里云的服务器。

说白了就是大家 可以一分钱不花,就可以领到服务器,规格是 2c4g(2vcpu 4G内存) 的机器。

有想参加的朋友,可以加我下微信,备注『服务器,我统一拉群,带大家一起薅羊毛。


   


喜欢明哥文章的同学
欢迎长按下图订阅!

⬇⬇⬇


浏览 53
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报