go语言 defer 你不知道的秘密!
go 语言的defer功能强大,对于资源管理非常方便,但是如果没用好,也会有陷阱哦.我们先来看几个例子.
例一: defer 是先进后出
这个很自然,后面的语句会依赖前面的资源,因此如果先前面的资源先释放了,后面的语句就没法玩了.
func main() {
var whatever []struct{} for i := range whatever {
defer fmt.Println(i)
}
}
这个输出应该很明显,就是4 3 2 1 0
例二: defer 碰上闭包
func main() {
var whatever []struct{}
for i := range whatever {
defer func() { fmt.Println(i) }()
} }
这个输出可能会超出某些人的意料,结果是4 4 4 4 4
其实go说的很清楚,我们一起来看看go spec如何说的
Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usualand saved anew but the actual function is not invoked.
也就是说函数正常执行,由于闭包用到的变量i在执行的时候已经变成4,所以输出全都是4.
例三: defer f.Close
这个大家用的都很频繁,但是go语言编程举了一个可能一不小心会犯错的例子.
type Test struct {
name string
}
func (t * Test) Close(){
fmt.Println(t.name," closed");
}
func main(){
ts:=[]Test{{"a"},{"b"},{"c"}}
for _,t := range ts{
defer t.Close()
}
}
这个输出并不会像我们预计的输出c b a,而是输出c c c
可是按照前面的go spec中的说明,应该输出c b a才对啊.
那我们换一种方式来调用一下.
例四: 像例一一样的调用
type Test struct {
name string
}
func (t * Test) Close(){
fmt.Println(t.name," closed");
}
func Close(t Test){
t.Close()
}
func main(){
ts:=[]Test{{"a"},{"b"},{"c"}}
for _,t := range ts{
Close(t)
}
}
这个时候输出的就是c b a
当然,如果你不想多写一个函数,也很简单,可以像下面这样,同样会输出c b a
例五:看似多此一举的声明
type Test struct {
name string
}
func (t * Test) Close(){
fmt.Println(t.name," closed");
}
func main(){
ts:=[]Test{{"a"},{"b"},{"c"}}
for _,t := range ts{
t2:=t
t2.Close()
}
}
通过以上例子,结合
Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usualand saved anew but the actual function is not invoked.
这句话.可以得出下面的结论:
defer后面的语句在执行的时候,函数调用的参数会被保存起来,但是不执行.也就是复制了一份.但是并没有说struct这里的this指针如何处理,通过这个例子可以看出go语言并没有把这个明确写出来的this指针当作参数来看待.
go语言 defer 你不知道的秘密!的更多相关文章
- C语言星号的秘密
C语言星号的秘密 星号的秘密 1.乘法运算符 2.定义指针 int *p = 0; 还是 int* p = 0;? 后一种比较容易这样理解:定义了一个变量p,它是指针型的(更详细一点,是指向int ...
- 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使用
defer Go语言中有种不错的设计,即延迟(defer)语句,你可以在函数中添加多个defer语句.当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回.特别是当你在进行一些打开资源 ...
- go语言defer关键字背后的实现,语法,用法
原文: https://tiancaiamao.gitbooks.io/go-internals/content/zh/03.4.html ------------------------------ ...
- 探究 Go 语言 defer 语句的三种机制
Golang 的 1.13 版本 与 1.14 版本对 defer 进行了两次优化,使得 defer 的性能开销在大部分场景下都得到大幅降低,其中到底经历了什么原理? 这是因为这两个版本对 defer ...
- 深入 Go 语言 defer 实现原理
转载请声明出处哦~,本篇文章发布于luozhiyun的博客: https://www.luozhiyun.com/archives/523 本文使用的go的源码 1.15.7 介绍 defer 执行规 ...
- go语言defer panic recover用法总结
defer defer是go提供的一种资源处理的方式.defer的用法遵循3个原则 在defer表达式被运算的同时,defer函数的参数也会被运算.如下defer的表达式println运算的同时,其入 ...
- Go 语言defer用法
defer延迟调用: 1.确保调用在函数结束时发生: 2.defer列表为先进后出: 3.通常在Open/Close Lock/Unlock中使用. defer调用顺序示例: package mai ...
随机推荐
- linux c++ rabbitMq Demo
1.在vs上实现远程调试Linux c++程序:https://www.jianshu.com/p/8b51a795cb92. 2.调试需要c++11,升级redhat上的gcc版本,虚拟机gcc版本 ...
- csdn知识库
- Android 截屏检测
最近项目中新接到一个需求,对手机截屏进行检测并进行后续操作,类似于Snapchat,iOS具有先天优势,因iOS系统提供了相关API!Google无果之后原作者决定再次造轮子,为了持续表达对Rx的敬意 ...
- ubuntu14.10下Qt5.4无法输入中文
最近学习Qt,于是在ubuntu下安装了开发环境.我是从官网上下载安装的Qt5.4版本.安装后发现在开发过程中无法输入中文.于是在网上搜了搜.解决办法如下: 1.安装fcitx-frontend-qt ...
- Xamarin官方示例代码无法部署,提示已跳过部署解决方法
最近利用Visual Studio 2017学习Android开发.主要是通过Xamarin官方的文档进行的.官方的入门指导提供了很多的示例代码.但是下载之后,调试运行的时候,总是无法部署到虚拟机上. ...
- mysql中的自定义函数
创建不带参数的自定义函数: 使用: 创建带参数的自定义函数: 使用: 创建具有复合结构的函数体的自定义函数:
- java Web中页面跳转方式之请求转发
1.在一个请求中跨越多个Servlet 2.多个Servlet在一个请求中,他们共享request对象.就是在Servlet01中setAttribute()保存数据在Servlet02中由getAt ...
- file_get_content() 超时
set_time_limit 只能影响php 程序的超时时间. file_get_contents 读取的是URL的超时时间. 因此 set_limit_limit 对file_get_conte ...
- ObjectMapper对象的使用 Object2JSON
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler ...
- msql 计算连续签到天数
刚刚写了一个签到计算天数的sql, 记录下来. 思路如下: 获取当前签到的最后时间(今天或昨天), 定义一个变量@i 对签到时间进行天数自减, 然后查询出当前记录签到时间是否与自减后的时间匹配. ...