预习内容

  • defer 的作用有哪些?
  • 多个 defer 的执行顺序是怎样的?
  • defer,return,函数返回值 三者之间的执行顺序

defer的作用

go中的defer延迟函数,一般是用于释放资源或者收尾工作

由于defer是具有延迟特性且执行动作是在函数return之后,因此作为资源释放作用再好不过。

  • 典型例子:释放锁、关闭文件、关闭链接
// 释放锁
func getValue() {
s.Lock()
defer s.Unlock()
...
} // 关闭文件
func read() {
f, err := os.OpenFile("filename", os.O_RDWR, os.ModePerm)
defer f.Close()
...
} // 关闭链接
func connect() {
resp, err := grequests.Get(s.cfg.GateApiCrossMarginUrl, nil)
defer resp.Close()
...
} // 收尾工作,defer 同时也是函数,可以做很多收尾相关工作
func closeConnection() {
...
defer func() {
file.close()
close(readChan)
}
...
}
  • 还有作用就是捕获 panic,这个功能在defer里也是典型用法
func sendChan() {
// 此处捕获 panic 进行 recover 防止程序崩溃
defer func() {
if ok := recover(); ok != nil {
fmt.Println("recover")
}
}()
// 向已经关闭的chan发送数据,此处会引起 panic
dataChan <- "message"
...
}

defer 释放资源『避坑指南』

资源释放动作一定紧跟资源使用(打开、连接)语句,不然defer可能不会被执行到,导致内存泄露

// 关闭文件
func read() error {
f1, err := os.OpenFile("filename", os.O_RDWR, os.ModePerm)
if err != nil {
return err
}
// 此时,defer还没执行到,提前return了,无效defer导致内存泄露
defer f1.Close() // 正确用法,紧跟资源使用语句
f2, err := os.OpenFile("filename", os.O_RDWR, os.ModePerm)
defer f2.Close()
if err != nil {
return err
}
}

defer 的调用顺序

墙裂建议不要先看后面的介绍做下面的题目,此处先跳过介绍defer调用顺序,看看下面比较典型的对defer顺序判断,你能看出来几个?

func deferFunc1(i int) (t int) {
t = i
defer func() {
t += 1
}()
return t
} func deferFunc2(i int) int {
t := i
defer func() {
t += 1
}()
return t
} func deferFunc3(i int) (t int) {
defer func() {
t += i
}()
return 1
} func deferFunc4() (t int) {
defer func(i int) {
fmt.Println(i)
fmt.Println(t)
}(t)
t = 0
return 1
} func ExecDeferFunc() {
// 猜猜下面输出的内容和顺序
fmt.Println(deferFunc1(1))
fmt.Println(deferFunc2(1))
fmt.Println(deferFunc3(1))
deferFunc4()
}

猜想结果可能是:2,2,1,0,0 或者 2,2,1,1,1 ?

估计比较模糊的地方应该是函数返回值 和 return value(函数返回值)关系不明确,还有就是对defer产生作用的时机不明确

正文开始!

再次强调defer是延迟函数,执行动作在return之后,defer相当于是将执行动作压入栈中,越是后面的defer越是先执行,执行顺序是LIFO(后进先出)

特别指出:有函数返回值的则return将结果写入返回值,defer进行收尾,可以看做 return最先执行,然后return将结果存入返回值,最后defer执行

那么基于刚刚的介绍再回头去看得到的『实际结果是:2,1,2,0,1』

复习内容

  • defer 用于资源释放和收尾工作
  • 多个 defer 调用顺序是 LIFO(后入先出),defer后的操作可以理解为压入栈中
  • defer,return,return value(函数返回值) 执行顺序:首先return,其次return value,最后defer。defer可以修改函数最终返回值。

『go成长之路』 defer 作用、典型用法以及多个defer调用顺序,附加defer避坑点,拿来吧你的更多相关文章

  1. 『NiFi 学习之路』简介

    『NiFi 学习之路』简介 『NiFi 学习之路』入门 -- 下载.安装与简单使用 『NiFi 学习之路』资源 -- 资料汇总 『NiFi 学习之路』把握 -- 架构及主要组件 『NiFi 学习之路』 ...

  2. 『NiFi 学习之路』自定义 —— 组件的自定义及使用

    一.概述 许多业务仅仅使用官方提供的组件不能够满足性能上的需求,往往要通过高度可定制的组件来完成特定的业务需求. 而 NiFi 提供了自定义组件的这种方式. 二.自定义 Processor 占坑待续 ...

  3. 『NiFi 学习之路』使用 —— 主要组件的使用

    一.概述 大部分 NiFi 使用者都是通过 NiFi 的 Processor 来实现自己的业务的.因此,我也主要就 NiFi 官方提供的 Porcessor 进行介绍. 二.Processor 如果你 ...

  4. 『NiFi 学习之路』把握 —— 架构及主要部件

    一.概述 通过前面几篇文章的学习,相信你对 NiFi 有了一个基础性的了解. 数据处理和分发系统 是什么概念? NiFi 系统中数据的传递方式是怎样的? NiFi 的重要 Processor 有哪些? ...

  5. 『NiFi 学习之路』资源 —— 资料汇总

    一.概述 由于 NiFi 是一个比较新的开源项目,国内的相关资料少之又少. 加之,大家都知道,国内的那么些个教程,原创都只是停留在初级使用阶段,没有更多深入的介绍. 再者,其余的文章不是东抄抄就是西抄 ...

  6. 『NiFi 学习之路』入门 —— 下载、安装与简单使用

    一.概述 "光说不练假把式." 官网上的介绍多少让人迷迷糊糊的,各种高大上的词语仿佛让 NiFi 离我们越来越远. 实践是最好的老师.那就让我们试用一下 NiFi 吧! 二.安装 ...

  7. 『王霸之路』从0.1到2.0一文看尽TensorFlow奋斗史

    ​ 0 序篇 2015年11月,Google正式发布了Tensorflow的白皮书并开源TensorFlow 0.1 版本. 2017年02月,Tensorflow正式发布了1.0.0版本,同时也标志 ...

  8. Android成长之路-LayoutInflater和inflate的用法

    在这里用Tabhost的例子来说明: package cn.csdn.activity; import android.app.TabActivity; import android.os.Bundl ...

  9. 『TensorFlow2.0正式版』TF2.0+Keras速成教程·零:开篇简介与环境准备

    此篇教程参考自TensorFlow 2.0 + Keras Crash Course,在原文的基础上进行了适当的总结与改编,以适应于国内开发者的理解与使用,水平有限,如果写的不对的地方欢迎大家评论指出 ...

随机推荐

  1. es6快速入门 系列 - async

    其他章节请看: es6 快速入门 系列 async 前文我们已经知道 promise 是一种异步编程的选择.而 async 是一种用于执行异步任务更简单的语法. Tip:建议学完 Promise 在看 ...

  2. 如何在国产龙芯架构平台上运行c/c++、java、nodejs等编程语言

    高能预警:本文内容过于硬核,涉及编译器原理.cpu指令集.机器码.编程语言原理.跨平台原理等计算机专业基础知识,建议具有c.c++.java.nodejs等多种编程语言开发能力,且实战经验丰富的资深开 ...

  3. kubernetes关闭基于角色的访问控制-匿名访问

    1.关闭基于角色的访问控制 如果正在使用一个带有RBAC机制的Kubernetes集群,服务账户可能不会被授权访问API服务器(或只有部分授权).目前最简单的方式就是运行下面的命令查询API服务器,从 ...

  4. 第14章:部署Java网站项目案例

    1 说明 (1) 项目迁移到k8s平台的流程 1) 制作镜像 dockerfile.docker+jenkins持续集成.镜像分类:基础镜像.中间镜像.项目镜像 2) 控制器管理pod 控制器管理po ...

  5. keycloak~管理平台的查询bug与自定rest中文检索

    对于keycloak来说,它的管理平台在它的源码中的admin-client中,它会定义相关的rest接口规范:在我们使用keycloak管理平台时,其中有一个组的查询,在我们查询中文组时,它是不支持 ...

  6. Mysql 主键的操作

    ​ 主键:primary key ,主要的键.一张表只能有一个字段可以使用对应的键,用来唯一的约束字段里面的数据,数据不能重复,这种键称之为主键,一张表只能最多有一个主键.  一.增加主键 方法一:在 ...

  7. AcWing 828. 模拟栈

    实现一个栈,栈初始为空,支持四种操作: (1) "push x" – 向栈顶插入一个数x: (2) "pop" – 从栈顶弹出一个数: (3) "em ...

  8. Spring缓存的注解关键词解释

    Spring缓存的注解关键词解释 @Cacheable支持缓存 @Cacheable可以标记在一个方法上,也可以标记在一个类上. 1.当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表 ...

  9. 不安装任何软件或脚本使用powershell快速计算文件的MD5/SHA1/SHA256等校验值

    有的时候在检查升级过程中需要对xml文件进行签名,而xml文件中一般都需要包含安装包的SHA256值,这里分享一个使用PowerShell快速计算SHA256等其他值的方法. 一.在需要计算文件SHA ...

  10. python使用笔记002

    一.字符串常用方法 1 s = ' ha.hahaha.' 2 print(s.count('a'))#找某一个元素在字符串里出现的次数 3 print(s.index('a'))#找某一个元素的下标 ...