Go-延时函数defer
关于延时调用函数(Deferred Function Calls)
延时调用函数基本语法如下:
defer func_name(param-list) {}
当一个函数前有关键字 defer 时,那么这个函数执行会被推迟到包含这个 defer 语句的函数即将返回前才执行,
如下示例:
package main
import "fmt"
func main() {
defer fmt.Println("Fourth")
fmt.Println("First")
fmt.Println("Third")
}
运行打印输出结果:
First
Third
Fourth
需要注意的是,defer 调用的函数参数,在定义 defer 时就已经被确定了,如下示例:
package main
import "fmt"
func main() {
i := 1
defer fmt.Println("Deferred print:",i)
i++
fmt.Println("Normal print:",i)
}
运行打印输出结果:
Normal print: 2
Deferred print: 1
从上面的结果中我们可以知道,在 defer fmt.Println("Deferred print:"i,) 调用时,i 的值就已经被确定了,因此相当
于 defer fmt.Println("Deferred print:",1)
需要强调的是,defer 调用的函数的参数值在 defer 定义时就已经被确定了,而 defer 函数内部所使用的变量的值需
要在运行时才确定。如下示例:
package main
import "fmt"
func f1() (r1 int) {
r := 1
defer func() {
r ++
fmt.Println(r)
}()
r = 2
return
}
func main() {
f1()
}
运行打印输出结果:
3
上面的例子中,我们看到最终打印的内容是 "3" ,这是因为在 "r = 2" 之后才执行的 defer 函数,因此在这个函数内,
r 的值是 2,自增后变成 3
defer 顺序
如果有多个 defer 调用,则调用的顺序是先进后出的顺序,类似于入栈出栈操作一样:
package main
import "fmt"
func main() {
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
defer fmt.Println(4)
}
运行打印输出结果:
4
3
2
1
defer 注意要点
defer 函数调用的执行时机是外层函数设置返回值之后,即将返回之前
如下示例:
package main
import "fmt"
func f1() (r int) {
defer func() {
r ++
}()
return 0
}
func main() {
fmt.Println(f1())
}
运行打印输出结果:
1
上面 fmt.Println(f1()) 打印的结果是 1,要弄明白这个问题,我们需要牢记两点:
1. defer 函数调用的执行时机是外层函数设置返回值之后,即将返回之前
2.return xxx 操作并不是原子
我们将上面的例子改写一下:
func f1() (r int) {
defer func() {
r ++
}()
r = 0
return
}
当进行赋值操作 r = 0 之后,才执行调用 defer 函数,最后才执行返回语句
下面我们再看一个例子:
package main
import "fmt"
func double(x int) int {
return x + x
}
func triple(x int) (r int) {
defer func() {
r += x
}()
return double(x)
}
func main() {
fmt.Println(triple(3))
}
上面的代码根据我们的讲解,可以改写成如下代码:
func triple(x int) (r int) {
r = double(x)
defer func() {
r += x
}()
return
}
---------------------------------------------------------------------2019/03/04------------------------------------------------------
转载地址:https://juejin.im/post/5b9b4acde51d450e5071d51f
参考文章:https://my.oschina.net/henrylee2cn/blog/505535
1:defer 在匿名返回值和有名返回值函数中的不同表现
先看下面两个方法执行的结果
func returnValues() int {
var result int
defer func() {
result++
fmt.Println("defer")
}()
return result
}
func namedReturnValues() (result int) {
defer func() {
result++
fmt.Println("defer")
}()
return result
}
上面的方法输出 0,下面的方法输出 1。上面的方法使用了匿名返回值,下面的方法使用了有名返回值,除此之外
逻辑都一样,但是为什么输出的结果的不一样呢?
1 多个 defer 的执行顺序为"先进后出"
2 所有函数在执行 return 返回指令之前,都会检查是否存在 defer 语句,如果存在将逆序调用 defer 语句执行完以后
在退出返回
3 有名返回值在函数声明的时候就已经被声明了,另外,return 不是一个原子操作,它包含前后两个步骤,第一步是:
给返回值赋值(如果是有名返回值则直接赋值,如果是匿名返回值则先声明再赋值);第二步是检查是否存在 defer 存在就
执行 defer, 最后结束函数运行
以匿名返回值为例,过程如下:
1. 因为匿名返回值并没有明确声明返回值,可以理解成 Go 自动创建声明了一个返回值 retValue ,然后将 result 赋值给
返回值 retValue
2.然后检查是否有 defer ,如果有则返回
3. 返回刚才创建的返回值
在这种情况下,defer 中的修改是对 result 执行的,而不是 retValue ,在有名返回值中,返回值已经在函数定义的时候就
已经被声明了,没有创建声明 retValue 的过程,直接赋值返回值
Go-延时函数defer的更多相关文章
- Golang入门教程(十三)延迟函数defer详解
前言 大家都知道go语言的defer功能很强大,对于资源管理非常方便,但是如果没用好,也会有陷阱哦.Go 语言中延迟函数 defer 充当着 try...catch 的重任,使用起来也非常简便,然而在 ...
- Android 如何通过代码模拟按钮点击 延时函数
View.performClick(); 比如: private Button mButton01; mButton01 = (Button)findViewById(R.id.myButt ...
- 延时函数出错,volatile一例
莫名其妙的错误.使用Systick做的延时. 初始化是这样的: //SysTick配置 SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); if ...
- JavaScript的sleep延时函数
JavaScript没有像Java的sleep延时函数,所以记录JavaScript的sleep延时函数 function sleep(milliSeconds) { var startTime = ...
- C# 非独占延时函数 非Sleep
在C#窗口程序中,如果在主线程里调用Sleep,在Sleep完成之前, 界面呈现出假死状态,不能响应任何操作! 下边实现的是非独占性延时函数,延时过时中界面仍可响应消息: public static ...
- Qt自定义sleep延时函数(巧妙的使用时间差,但这样似乎CPU满格,而不是沉睡)
Qt不像VC++的win32/MFC编程那样,提供了现成的sleep函数可供调用.Qt把sleep函数封装在QThread类中.子线程可以调用sleep函数.但是如果用户想在主线程实现延时功能,该怎么 ...
- 改进的延时函数Delay(使用MsgWaitForMultipleObjects等待消息或超时的到来)
解决上一节中延时函数占CPU使用率(达50%)的第二种方法是利用消息机制,通过API函数MsgWaitForMultipleObjects等待消息或超时的到来,从而避免使用循环检测使CPU占用率过高. ...
- stm32中的延时函数
//粗延时函数,微秒 void delay_nus(u16 time) { u16 i=0; while(time--) { i=10; //自己定义 while(i--) ; } } //毫秒级的 ...
- QT 延时函数设置
QT 的延时函数分为非阻塞延时 和 阻塞型延时 非阻塞延时: void GreenPass3::delaymsec(int msec){ QTime dieTime = QTime::curre ...
- Go 延迟函数 defer 详解
Go 延迟函数 defer 详解 Go 语言中延迟函数 defer 充当着 try...catch 的重任,使用起来也非常简便,然而在实际应用中,很多 gopher 并没有真正搞明白 defer.re ...
随机推荐
- .net拼接json字符串
{ while (reader.Read()) { if (reader.HasRows) { JSONstring += "{"; JSONstring += "\&q ...
- 学习MySQL过程中的随笔一
第一天: 关于安装出现了很多问题,各种不懂的bug,没得法只能在网上查找解决方法,终于!!! 登录成功了,一下午的时间 附上参考资料:https://blog.csdn.net/weibo_boer/ ...
- 微信小程序wx.uploadFile 上传文件 的两个坑
fileUpload: function (tempFilePath) { var that = this;//坑1: this需要这么处理 wx.uploadFile({ url: url地址, / ...
- face++静态库转为动态库
前言 苹果商店上架应用,有规定支持iOS8.0以上的iPA可执行文件的大小不能超过60M. face++提供过来的是静态库,会导致苹果上架的ipa的包增加1.5M左右.而刚好我们的APP包Mach-O ...
- React 学习过程中常见的错误
1, react报错Module not found: Error: Can't resolve 解决: 一般是加载文件的路径写错了:
- 1.1大数据平台架构及Hadoop生态圈
1.硬件架构实例 2.软件架构实例 3.数据流通用概念模型 a.数据源(互联网.物联网.企业数据):App.Device.Site b.数据收集(ETL.提取.转换.加载):Flume.Kafka.S ...
- 微信小程序之图片base64解码
不知道大家在做微信小程序的时候遇到base64解码的问题,我之前在做微信小程序的时候遇到base64解析图片一直有问题,所以在这里把遇到的问题和解决方案在这里记录一下: 在平时的项目中我们是直接用ba ...
- IDEA 201809 Jrebel安装破解
jrebel介绍: JRebel是一款JAVA虚拟机插件,它使得JAVA程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响.JRebel使你能即时分别看到代码.类和资源的变化, ...
- 在sql中case子句的两种形式
case子句,在select后面可以进行逻辑判断. 两种形式:判断相等.判断不等 一.判断相等的语法: case 列名 when ... then ... when ... then ... el ...
- JavaFX-Stage
1.Stage类继承自Window类,继承了Window类的show()方法,Stage的close()方法实际上是调用了继承自Window类的hide()方法.另外还有Window的setOpaci ...