什么是defer

defer是Go语言提供的一种用于注册延迟调用的机制:让函数或语句可以在当前函数执行完毕后(包括通过return正常结束或者panic导致的异常结束)执行。

defer的应用场景

defer语句通常用于一些成对操作的场景:打开连接/关闭连接;加锁/释放锁;打开文件/关闭文件等。

defer的原理

defer语句并不会马上执行,而是会进入一个栈,函数return前,会按先进后出(FILO)的顺序执行。也就是说最先被定义的defer语句最后执行。先进后出的原因是后面定义的函数可能会依赖前面的资源,自然要先执行;否则,如果前面先执行,那后面函数的依赖就没有了。

defer的引用方式

defer语句定义时,对外部变量的引用有如下两种方式:

1.作为函数参数和作为闭包引用。作为函数参数,则在defer定义时就把值传递给defer,并被缓存起来。

2.作为闭包引用的话,则会在defer函数真正调用时根据整个上下文确定当前的值。

defer的踩坑点

避免踩坑的关键是要理解这条语句:

return xxx

这条语句经过编译之后,会变成了三条指令:

1. 返回值 = xxx
2. 调用defer函数
3. 空的return

第1,3 步才是return 语句真正的命令,第2步是 defer的定义语句,这里就有可能会操作返回值。

代码示例

示例1:

func f() (r int) {
defer func() {
r++
}()
return 0
}

拆解过程:

func f() (r int) {

    // 1.赋值
r = 0 // 2.闭包引用,返回值被修改
defer func() {
r++
}() // 3.空的return
return
}

由于defer是闭包引用,返回值被修改,所以f()返回 1。

示例2:

func f() (r int) {
t := 5
defer func() {
t = t + 5
}()
return t
}

拆解过程:

func f() (r int) {
t := 5
// 1.赋值
r = t // 2.闭包引用,但是没有修改返回值r
defer func() {
t = t + 5
}() // 3.空的return
return
}

由于第2步未涉及返回值r的操作,所以返回5。

示例3:

func f() (r int) {
defer func(r int) {
r = r + 5
}(r)
return 1
}

拆解过程:

func f() (r int) {

    // 1.赋值
r = 1 // 2.r作为函数参数,不会修改要返回的那个r值
defer func(r int) {
r = r + 5
}(r) // 3.空的return
return
}

由于第2步中r是作为函数参数使用,只是一份拷贝,defer语句里面的r和外面的r其实是两个变量,里面变量r的改变不会影响外层变量r,所以不是返回6,而是返回1。


个人主页:

www.codeapes.cn

GO语言学习笔记5-defer的使用的更多相关文章

  1. GO语言学习笔记(一)

    GO语言学习笔记 1.数组切片slice:可动态增长的数组 2.错误处理流程关键字:defer panic recover 3.变量的初始化:以下效果一样 `var a int = 10` `var ...

  2. Go语言学习笔记(1)——顺序编程

    Go语言学习笔记这一堆主要是<Go语言编程>(人民邮电出版社)的读书笔记.中间会穿插一些零碎的点,比如源码学习之类的.大概就是这样吧. 1. 顺序编程 1.1 变量 变量的声明: var ...

  3. HTML语言学习笔记(会更新)

    # HTML语言学习笔记(会更新) 一个html文件是由一系列的元素和标签组成的. 标签: 1.<html></html> 表示该文件为超文本标记语言(HTML)编写的.成对出 ...

  4. 2017-04-21周C语言学习笔记

    C语言学习笔记:... --------------------------------- C语言学习笔记:学习程度的高低取决于.自学能力的高低.有的时候生活就是这样的.聪明的人有时候需要.用笨的方法 ...

  5. 2017-05-4-C语言学习笔记

    C语言学习笔记... ------------------------------------ Hello C语言:什么是程序:程序是指:完成某件事的既定方式和过程.计算机中的程序是指:为了让计算机执 ...

  6. Haskell语言学习笔记(88)语言扩展(1)

    ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...

  7. Go语言学习笔记十三: Map集合

    Go语言学习笔记十三: Map集合 Map在每种语言中基本都有,Java中是属于集合类Map,其包括HashMap, TreeMap等.而Python语言直接就属于一种类型,写法上比Java还简单. ...

  8. Go语言学习笔记十二: 范围(Range)

    Go语言学习笔记十二: 范围(Range) rang这个关键字主要用来遍历数组,切片,通道或Map.在数组和切片中返回索引值,在Map中返回key. 这个特别像python的方式.不过写法上比较怪异使 ...

  9. Go语言学习笔记十一: 切片(slice)

    Go语言学习笔记十一: 切片(slice) 切片这个概念我是从python语言中学到的,当时感觉这个东西真的比较好用.不像java语言写起来就比较繁琐.不过我觉得未来java语法也会支持的. 定义切片 ...

  10. Go语言学习笔记十: 结构体

    Go语言学习笔记十: 结构体 Go语言的结构体语法和C语言类似.而结构体这个概念就类似高级语言Java中的类. 结构体定义 结构体有两个关键字type和struct,中间夹着一个结构体名称.大括号里面 ...

随机推荐

  1. python学习之模块-模块(二)

    5.2 序列化模块 ​ 将一种数据结构转换成一种特殊的序列(字符串或bytes)的过程就叫序列化.这个特殊的序列还可以通过命令反解回原来的数据类型. python中有三种序列化的功能模块: json模 ...

  2. Mac_Navicat Premium连接MySQL错误2059 - Authentication plugin 'caching_sha2_password' cannot be loaded: dlopen(../Frameworks/caching_sha2_password.so, 2): image not found

    mac下MySql启动连接报错:Authentication plugin ‘caching_sha2_password’ cannot be loaded: dlopen(/usr/local/my ...

  3. 【VS开发】ActiveX开发注意事项

    [VS开发]ActiveX开发注意事项 标签:[VS开发] 注意:必须在工程的app文件的InitInstance()中加入如下代码,否则动态创建控件不会成功: AfxEnableControlCon ...

  4. Revo Uninstaller Pro - 真正彻底卸载软件不留垃圾的强大神器!(清理安装残留文件/注册表)

    大家都知道 Windows 在卸载软件时总是不够彻底,系统C盘总会留下大量难以辨别和清理的垃圾文件和临时文件,时间长了注册表也会变得非常臃肿,不仅浪费硬盘空间,而且也会明显拖慢系统响应和启动速度. R ...

  5. SpringBoot项目集成cas单点登录

    添加依赖 添加cas client依赖 <dependency> <groupId>net.unicon.cas</groupId> <artifactId& ...

  6. (转)在Kubernetes集群中使用JMeter对Company示例进行压力测试

    背景 压力测试是评估应用性能的一种有效手段.此外,越来越多的应用被拆分为多个微服务而每个微服务的性能不一,有的微服务是计算密集型,有的是IO密集型. 因此,压力测试在基于微服务架构的网络应用中扮演着越 ...

  7. XSS跨站简析

    XSS跨站脚本原理 当应用程序发送给浏览器的页面中包含用户提交的数据,但没有经过适当验证或转义时,就会导致跨站脚本漏洞 这个“跨”实际上属于浏览器的特性,而不是缺陷 (参考:浏览器同源策略) 不去直接 ...

  8. google map api key配置

    https://console.cloud.google.com/google/maps-apis/apis/maps-backend.googleapis.com/credentials?proje ...

  9. C语言--- 高级指针2(结构体指针,数组作为函数参数)

    一.结构体指针 1. 什么是结构体指针?指向结构体变量的指针     结构体:     typedef  struct stu{                          char name[ ...

  10. Linux普通用户无法使用sudo

    问题描述: jenkins执行发布脚本,因为使用的是jenkins用户,所以有些shell命令需要 sudo 来执行,导致报错. + sudo rm -rf /usr/share/nginx/html ...