Go语言defer分析
什么是defer?
defer语句是专门在函数结束以后做一些清理工作的。我们先举一个例子来更好的理解,现在有一个函数,它的作用是把一个文件内容拷贝到另一个文件。
func CopyFile(dstName string, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
dst, err := os.Create(dstName)
if err != nil {
return
}
written, err = io.Copy(dst, src)
src.Close()
dst.Close()
return
}
以上代码是可以正常执行的,但是存在一个问题,如果os.Create执行失败,那么就无法执行到文件资源的Close函数。进程每打开一个文件就会占用一个文件描述符,而在系统当中,文件描述符是有上限的,可以通过ulimit -n查看,如果资源没有被及时释放,会出现资源浪费的情况。如果打开文件过多,也会出现Too many open files的提示。这个时候就需要通过defer来解决问题了,代码如下。
func CopyFile(dstName string, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()
written, err = io.Copy(dst, src)
return
}
defer语句会在return参数设置之后、函数返回给调用者之前执行,这样就不再担心文件资源无法被Close了。
defer的三个规则
规则一:被deferred的函数参数在defer时确定
func a() {
i := 0
defer fmt.Println(i)
i++
return
}
我们通过以上代码来理解这个拗口的规则,如果根据官方的定义来理解这段代码,变量i的值铁定为1,但实际执行的结果不是1,却是0。
Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked. Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred.
那我们再重新来理解这个规则,变量i是在逐行执行到defer语句的时候就已经确定了值,这个时候变量i还没有进行自增,所以输出的结果应该是0而不是1。
规则二:被deferred函数执行顺序遵循LIFO原则
func b() {
for i := 0; i < 4; i++ {
defer fmt.Print(i)
}
}
LIFO全称为Last In First Out,意为后进先出,栈是一种典型的LIFO数据结构。defer也是如此,拿以上代码为例,先后遍历了四次,也就是做了四次压栈操作。同理,在函数return之前,就会逐一出栈,倒序执行defer语句,所以上述代码输出内容为3210。

规则三:deferred函数可以读取和修改函数的返回值
func c() (i int) {
defer func() { i++ }()
return 1
}
我们定义一个defer函数,将变量i自增,那么最终变量i的值为2。我们从官方文档中可以看出,defer语句是在函数设置返回值后,且在返回给主调函数前执行的,根据这个思路,c函数已经return了1,这个时候执行了defer函数,将返回的结果1进行了自增,然后返回给主调函数,这个时候主调函数拿到的值就是2了。
deferred functions are executed after any result parameters are set by that return statement but before the function returns to its caller
Go语言defer分析的更多相关文章
- R语言︱情感分析—词典型代码实践(最基础)(一)
每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 笔者寄语:词典型情感分析对词典要求极高,词典中 ...
- 【转】对 Rust 语言的分析
对 Rust 语言的分析 Rust 是一门最近比较热的语言,有很多人问过我对 Rust 的看法.由于我本人是一个语言专家,实现过几乎所有的语言特性,所以我不认为任何一种语言是新的.任何“新语言”对我来 ...
- C语言内存分析
C语言内存分析 一.进制 概念:进制是一种计数方式,是数值的表现形式 4种主要的进制: ①. 十进制:0~9 ②. 二进制:0和1 ③. 八进制:0~7 ④. 十六进制:0~9+a b c d e f ...
- go语言 defer 高级
go语言defer语句的用法 defer的语法 defer后面必须是函数调用语句,不能是其他语句,否则编译器会出错. package main import "log" func ...
- go语言---defer
go语言---defer https://blog.csdn.net/cyk2396/article/details/78885135 defer 是在函数退出前调用,多个defer遵循 先进后出 的 ...
- 深入 Go 语言 defer 实现原理
转载请声明出处哦~,本篇文章发布于luozhiyun的博客: https://www.luozhiyun.com/archives/523 本文使用的go的源码 1.15.7 介绍 defer 执行规 ...
- go语言defer使用
defer Go语言中有种不错的设计,即延迟(defer)语句,你可以在函数中添加多个defer语句.当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回.特别是当你在进行一些打开资源 ...
- R语言︱情感分析—基于监督算法R语言实现(二)
每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 笔者寄语:本文大多内容来自未出版的<数据 ...
- go语言 defer 你不知道的秘密!
go 语言的defer功能强大,对于资源管理非常方便,但是如果没用好,也会有陷阱哦.我们先来看几个例子. 例一: defer 是先进后出 这个很自然,后面的语句会依赖前面的资源,因此如果先前面的资源先 ...
随机推荐
- <BZOJ3032>七夕祭
水 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> ...
- html解析过程
Web页面运行在各种各样的浏览器当中,浏览器载入.渲染页面的速度直接影响着用户体验 简单地说,页面渲染就是浏览器将html代码根据CSS定义的规则显示在浏览器窗口中的这个过程.先来大致了解一下浏览器都 ...
- 用shell脚本新建文件并自动生成头说明信息
目标: 新建文件后,直接给文件写入下图信息 代码实现: [root@localhost test]# vi AutoHead.sh #!/bin/bash #此程序的功能是新建shell文件并自动生成 ...
- 360若真入股HTC 到底是谁来拯救谁
到底是谁来拯救谁" title="360若真入股HTC 到底是谁来拯救谁"> 我总是持有一种观点,那就是拯救是相互的.就像老师拯救"堕落"学生, ...
- Android编程权威指南(第2版)--第16章 使用intent拍照 挑战练习
16.7挑战练习:优化照片显示 新建dialog_photo.xml 1234567891011121314 <?xml version="1.0" encoding=&qu ...
- ODI学习资料
ODI12.2.1.4入门指南:https://docs.oracle.com/en/middleware/fusion-middleware/data-integrator/12.2.1.4/ind ...
- Linux命令学习神器!命令看不懂直接给你解释!
大家都知道,Linux 系统有非常多的命令,而且每个命令又有非常多的用法,想要全部记住所有命令的所有用法,恐怕是一件不可能完成的任务. 一般情况下,我们学习一个命令时,要么直接百度去搜索它的用法,要么 ...
- PostgreSQL没有认证密码就登陆了缘由
上午同事爆出这样的问题,使用正确的用户名和错误的密码连接了postgresql数据库,竟然连上了.这不是故意这样神操作,不小心密码写错了,咋一看这样怎么能行,随便输入一个密码都能登陆上.自己测试也是同 ...
- 一文看懂js中元素偏移量(offsetLeft,offsetTop,offsetWidth,offsetHeight)
偏移量(offset dimension) 偏移量:包括元素在屏幕上占用的所有可见空间,元素的可见大小有其高度,宽度决定,包括所有内边距,滚动条和边框大小(注意,不包括外边距). 以下4个属性可以获取 ...
- 玩转 React(五)- 组件的内部状态和生命周期
文章标题总算是可以正常一点了-- 通过之前的文章我们已经知道:在 React 体系中所谓的 "在 JavaScript 中编写 HTML 代码" 指的是 React 扩展了 Jav ...