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


Posted in Golang onMarch 25, 2022

什么是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 := 1
	defer fmt.Println(test(i))
	i = 100
}

func test(i int) int {
	i = i + 1
	return 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 := 1
	defer func() {
		fmt.Println(test(i))
	}()
	i = 100
}

func test(i int) int {
	i = i + 1
	return 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

总结

到此这篇关于Golang中defer预计算参数的文章就介绍到这了,更多相关Go defer预计算参数内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Golang 相关文章推荐
Golang 正则匹配效率详解
Apr 25 Golang
golang如何去除多余空白字符(含制表符)
Apr 25 Golang
goland 清除所有的默认设置操作
Apr 28 Golang
go语言中json数据的读取和写出操作
Apr 28 Golang
golang 如何通过反射创建新对象
Apr 28 Golang
基于Go Int转string几种方式性能测试
Apr 28 Golang
Golang 编译成DLL文件的操作
May 06 Golang
浅谈Golang 切片(slice)扩容机制的原理
Jun 09 Golang
Go语言基础map用法及示例详解
Nov 17 Golang
简单聊聊Golang中defer预计算参数
Mar 25 Golang
golang操作rocketmq的示例代码
Apr 06 Golang
Golang 1.18 多模块Multi-Module工作区模式的新特性
Apr 11 Golang
Go 中的空白标识符下划线
golang生成vcf通讯录格式文件详情
golang实现浏览器导出excel文件功能
Golang使用Panic与Recover进行错误捕获
Mar 22 #Golang
Go语言特点及基本数据类型使用详解
详解Golang如何优雅的终止一个服务
Mar 21 #Golang
Go语言实现一个简单的并发聊天室的项目实战
Mar 18 #Golang
You might like
php获取远程图片的两种 CURL方式和sockets方式获取远程图片
2011/11/07 PHP
详解PHP内置访问资源的超时时间 time_out file_get_contents read_file
2013/06/03 PHP
jquery $.each()使用探讨
2013/09/23 Javascript
JS对img标签进行优化使用onerror显示默认图像
2014/04/24 Javascript
如何让浏览器支持jquery ajax load 前进、后退功能
2014/06/12 Javascript
js在IE与firefox的差异集锦
2014/11/11 Javascript
JavaScript操作XML文件之XML读取方法
2015/06/09 Javascript
ECMAScript6中Map/WeakMap详解
2015/06/12 Javascript
apply和call方法定义及apply和call方法的区别
2015/11/15 Javascript
window.onload绑定多个事件的两种解决方案
2016/05/15 Javascript
微信小程序 后台登录(非微信账号)实例详解
2017/03/31 Javascript
ES6新特性八:async函数用法实例详解
2017/04/21 Javascript
VueJS如何引入css或者less文件的一些坑
2017/04/25 Javascript
vue-cli配置全局sass、less变量的方法
2019/06/06 Javascript
Vue之Mixins(混入)的使用方法
2019/09/24 Javascript
[48:48]VGJ.T vs Liquid 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
Python实现单词拼写检查
2015/04/25 Python
在Python中处理日期和时间的基本知识点整理汇总
2015/05/22 Python
Python设计模式编程中解释器模式的简单程序示例分享
2016/03/02 Python
解决nohup执行python程序log文件写入不及时的问题
2019/01/14 Python
python框架Django实战商城项目之工程搭建过程图文详解
2020/03/09 Python
python hmac模块验证客户端的合法性
2020/11/07 Python
calendar在python3时间中常用函数举例详解
2020/11/18 Python
python 基于opencv实现高斯平滑
2020/12/18 Python
UGG英国官方网站:UGG UK
2018/02/08 全球购物
电子信息专业学生自荐信
2013/11/09 职场文书
企划专员岗位职责
2013/12/09 职场文书
教师一岗双责责任书
2014/04/16 职场文书
团结就是力量演讲稿
2014/05/21 职场文书
公司任命书模板
2014/06/06 职场文书
让世界充满爱观后感
2015/06/10 职场文书
幼儿教师远程研修感悟
2015/11/18 职场文书
2016大一新生军训心得体会
2016/01/11 职场文书
医学生自荐信范文(2016精选篇)
2016/01/28 职场文书
python使用glob检索文件的操作
2021/05/20 Python
Spring中的@Transactional的工作原理
2022/06/05 Java/Android