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 你不知道的秘密!的更多相关文章

  1. C语言星号的秘密

    C语言星号的秘密 星号的秘密 1.乘法运算符   2.定义指针 int *p = 0; 还是 int* p = 0;? 后一种比较容易这样理解:定义了一个变量p,它是指针型的(更详细一点,是指向int ...

  2. go语言 defer 高级

    go语言defer语句的用法 defer的语法 defer后面必须是函数调用语句,不能是其他语句,否则编译器会出错. package main import "log" func ...

  3. go语言---defer

    go语言---defer https://blog.csdn.net/cyk2396/article/details/78885135 defer 是在函数退出前调用,多个defer遵循 先进后出 的 ...

  4. go语言defer使用

    defer Go语言中有种不错的设计,即延迟(defer)语句,你可以在函数中添加多个defer语句.当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回.特别是当你在进行一些打开资源 ...

  5. go语言defer关键字背后的实现,语法,用法

    原文: https://tiancaiamao.gitbooks.io/go-internals/content/zh/03.4.html ------------------------------ ...

  6. 探究 Go 语言 defer 语句的三种机制

    Golang 的 1.13 版本 与 1.14 版本对 defer 进行了两次优化,使得 defer 的性能开销在大部分场景下都得到大幅降低,其中到底经历了什么原理? 这是因为这两个版本对 defer ...

  7. 深入 Go 语言 defer 实现原理

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客: https://www.luozhiyun.com/archives/523 本文使用的go的源码 1.15.7 介绍 defer 执行规 ...

  8. go语言defer panic recover用法总结

    defer defer是go提供的一种资源处理的方式.defer的用法遵循3个原则 在defer表达式被运算的同时,defer函数的参数也会被运算.如下defer的表达式println运算的同时,其入 ...

  9. Go 语言defer用法

    defer延迟调用: 1.确保调用在函数结束时发生: 2.defer列表为先进后出: 3.通常在Open/Close  Lock/Unlock中使用. defer调用顺序示例: package mai ...

随机推荐

  1. PHP面向对象深入研究之【对象生成】

    对象 看个例子 <?php abstract class Employee { // 雇员 protected $name; function __construct( $name ) { $t ...

  2. thinkPHP增删改查的方法案例

    thinkphp对数据库增删改查进行了封装操作,使得使用更加方便,但是不一定灵活. 可以用封装的用,需要写sql,可以执行sql. 1.原始的 $Model = new Model(); // 实例化 ...

  3. 转:Oracle里几组重要的视图--v$sysstat,v$system_event,v$parameter v$system_parameter

    按组分的几组重要的性能视图 1.System 的 over view v$sysstat , v$system_event  , v$parameter,V$instance得到oracle_sid ...

  4. git的分布式和集中式

    当然,Git的优势不单是不必联网这么简单,后面我们还会看到Git极其强大的分支管理,把SVN等远远抛在了后面.

  5. timequest学习之黑金动力(一)

    黑金动力的资料还是非常有价值的.通过建模篇,对于给定的时序关系,我总能实现.但是,这总是很初级的能力.也只是为后面的建模服务.所以,现阶段我的能力还是非常有限.我相信我一定会成为牛人,能够独挡一面.借 ...

  6. Python实现SSH连接远程服务器

    首先需要安装paramiko模块 #-*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR" import paramiko ssh = p ...

  7. python--open用法

    open/文件操作f=open('/tmp/hello','w') #open(路径+文件名,读写模式) #读写模式:r只读,r+读写,w新建(会覆盖原有文件),a追加,b二进制文件.常用模式 如:' ...

  8. linux下FTP使用

    如何在linux下开启FTP服务 1. 首先服务器要安装ftp软件,查看是否已经安装ftp软件下:    #which vsftpd    如果看到有vsftpd的目录说明服务器已经安装了ftp软件 ...

  9. 继承ServletContextListener可以完成的事情

    1.定时任务: 定时任务是从某个固定的时间开始执行特定的程序,继承这个方法,可以实现刚启动项目的时候执行某特定的程序,完成给客户部署的时即可以看到某个页面的效果. 2.初始化系统常量等: 这样来完成系 ...

  10. C语言语法目录二

    1.char类型 char c;定义了一个char变量 'a' ; char常量 char的本质就是一个整数,一个只有一个字节大小的整数 char c; 定义一个有符号的char unsigned c ...