Defer 的变量快照什么情况会失效?

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

[[433813]]

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

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

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

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

  1. func func1() { 
  2.     age := 0 
  3.     defer fmt.Println(age) // output: 0 
  4.  
  5.     age = 18 
  6.     fmt.Println(age)      // output: 18 
  7.  
  8.  
  9. func main() { 
  10.     func1() 

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

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

  1. func func1() { 
  2.     age := 0 
  3.     defer func() { 
  4.         fmt.Println(age) 
  5.     }() 
  6.     age = 18 
  7.     return 
  8.  
  9. func main() { 
  10.     func1() 

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

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

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

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

总结一下:

  • 若 defer 后接的是单行表达式,那defer 中的 age 只是拷贝了 func1 函数栈中 defer 之前的 age 的值;
  • 若 defer 后接的是闭包函数,那defer 中的 age 只是存储的是 func1 函数栈中 age 的指针。

本文转载自微信公众号「Go编程时光」,可以通过以下二维码关注。转载本文请联系Go编程时光公众号。

 

责任编辑:武晓燕 来源: Go编程时光
相关推荐

2022-09-14 19:50:22

事务场景流程

2022-06-27 07:23:44

MySQL常量优化

2012-04-25 09:24:40

Android

2021-04-13 13:18:11

数字货币加密货币区块链

2022-04-13 20:53:15

Spring事务管理

2011-12-11 11:51:28

2023-11-23 23:52:06

options请求浏览器

2011-12-28 15:24:21

2021-04-23 23:19:26

加密货币稳定币比特币

2013-09-04 15:17:38

2015-11-23 14:29:16

流量提速降费运营商

2010-07-13 16:07:26

SQL Server行

2013-09-12 10:41:39

VDI部署

2021-09-14 07:26:25

雪花算法ID

2013-07-29 14:50:43

API

2021-04-15 08:01:27

Spring声明式事务

2015-06-01 06:39:18

JavaJava比C++

2020-11-18 09:26:52

@property装饰器代码

2020-09-24 09:43:59

Http协议options请求

2020-10-16 17:20:21

索引MySQL数据库
点赞
收藏

51CTO技术栈公众号