简单聊聊Golang中defer预计算参数

news/2024/7/8 1:31:10
在golang当中defer代码块会在函数调用链表中增加一个函数调用,下面这篇文章主要给大家介绍了关于Golang中defer预计算参数的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

什么是defer

defer用来声明一个延迟函数,把这个函数放入到一个栈上, 当外部的包含方法return之前,返回参数到调用方法之前调用,也可以说是运行到最外层方法体的"}"时调用。我们经常用他来做一些资源的释放,比如关闭io操作

func doSomething(fileName string) {file,err := os.Open(fileName)if err != nil {panic(err)}defer file.Close()
}

defer 可以保证方法可以在外围函数返回之前调用。有点像其他言的 try finally

try{
}finally{
}

Go语言defer预计算参数

Go 语言中所有的函数调用都是传值的,虽然 defer 是关键字,但是也继承了这个特性。假设我们想要计算 main 函数运行的时间,可能会写出以下的代码:

package main
import ("fmt""time"
)func main() {startedAt := time.Now()defer fmt.Println(time.Since(startedAt))time.Sleep(time.Second) //休眠一秒
}

结果是:

D:\workspace\go\src\test>go run main.go
0s 

运行结果并不符合我们的预期,这个现象背后的原因是什么呢?经过分析,我们会发现调用 defer 关键字会立刻拷贝函数中引用的外部参数,所以 time.Since(startedAt) 的结果不是在 main 函数退出之前计算的,而是在 defer 关键字调用时计算的【defer入栈的时候】,最终导致上述代码输出 0s

我们再来看个简单例子来说明上述解释:

package main
import ("fmt"
)func main() {i := 1defer fmt.Println(test(i))i = 100
}func test(i int) int {i = i + 1return i
} D:\workspace\go\src\test>go run main.go
2

当代码运行到defer fmt.Println(test(i))的时候,会把defer右边最外层函数的参数计算完毕,并传递进函数里,但不会执行函数体的代码直到包裹defer的函数返回。我们先看会把defer右边最外层函数的参数计算完毕,并传递进函数里这句话,对应例子就是先把test(i)算出来,此时i=1,计算test(1)得2,然后fmt.Println(2)入栈,等到最后程序运行完了再运行defer结果就是2(但不会执行函数体的代码直到包裹defer的函数返回)。

我们再来看一个例子与匿名函数结合:

package main
import ("fmt"
)func main() {i := 1defer func() {fmt.Println(test(i))}()i = 100
}func test(i int) int {i = i + 1return i
}

结果:

D:\workspace\go\src\test>go run main.go
101  

使用匿名函数,结果是101,相当于i给到test方法的是100,那为什么呢?还是那句话:但不会执行函数体的代码直到包裹defer的函数返回

也就是说他会把整个{ fmt.Println(test(i)) }()函数体入栈,等到最后程序运行完了再运行defer,此时的i是100,运行test后就是101了。

所以你要解决第一个打印为0s的问题,你就可以使用匿名函数来解决,如下:

package main
import ("fmt""time"
)func main() {startedAt := time.Now()defer func() {fmt.Println(time.Since(startedAt))}()time.Sleep(time.Second) //休眠一秒
}

结果:

D:\workspace\go\src\test>go run main.go
1.0152825s

http://lihuaxi.xjx100.cn/news/281189.html

相关文章

【unity HoloLens2】触碰了物体但没反应,触碰了一次却调用多次,HoloLens2的touch触发机制探究

【unity HoloLens2】触碰了物体但没反应,触碰了一次却调用多次,HoloLens2的touch触发机制探究 开发项目时发现,有时候触碰了物体却没有触发touch事件,有时候触碰了一次物体,却触发了两次事件,经过测试发现…

600页!分享珍藏很久的《推荐系统学习手册》(附链接)

这是之前学习推荐系统时的学习资料,非常全面,包含经典模型的解析及代码实现、模型的评估、最新工业界论文解读等等,全网仅此一份!该手册有PDF版本和Markdown版本,总计有600多页!资料领取方式:1.…

轻松应对Java试题,这是一份大数据分析工程师面试指南

作者 | HappyMint转载自大数据与人工智能(ai-big-data)导语:经过这一段时间与读者的互动与沟通,本文作者发现很多小伙伴会咨询面试相关的问题,特别是即将毕业的小伙伴,所以决定输出一系列面试相关的文章。本…

flash写保护原理_STM32系统中的2种数据掉电保护方法!

在嵌入式设备开发中,往往需要保存一些掉电不易失性的数据,如果系统配置、用户定制信息等等,如果增加额外的ROM IC,比如(基于I2C的24C02等等)往往会造成额外的PCB空间增大,硬件成本增加&#xff…

Java重写父类使用@Override时出现The method destroy() of type xxx must override a superclass method的问题解决...

解决方法: 1、把JDK版本改成1.6以上的。 2、把Compiler改成1.6以上的。 关于这两者的区别,参考:http://www.cnblogs.com/EasonJim/p/6741682.html

《深入理解Spring Cloud与微服务构建》出版啦!

作者简介方志朋,毕业于武汉理工大学,CSDN博客专家,专注于微服务、大数据等领域,乐于分享,爱好开源,活跃于各大开源社区。著有《史上最简单的Spring Cloud教程》,累计访问量超过了300万。本书源码…

Perl split字符串分割函数用法指南

本文向大家简单介绍一下Perl split函数的用法,Perl中的一个非常有用的函数是Perl split函数-把字符串进行分割并把分割后的结果放入数组中。 本文和大家重点讨论一下Perl split函数的用法,Perl中的一个非常有用的函数是Perl split函数-把字符串进行分割并…

特斯拉的计算机视觉

点击上方“小白学视觉”,选择加"星标"或“置顶”重磅干货,第一时间送达1.任务根据埃隆马斯克(Elon Musk)的说法,截至2020年7月初,特斯拉接近于自动驾驶汽车,也称为5级自动驾驶。无论是…