defer

Go语言中有种不错的设计,即延迟(defer)语句,你可以在函数中添加多个defer语句。当函数执行到最后时,这些defer语句会按照逆序执行, 最后该函数返回。特别是当你在进行一些打开资源的操作时,遇到错误需要提前返回,在返回前你需要关闭相应的资源,不然很容易造成资源泄露等问题。如下代码 所示,我们一般写打开一个资源是这样操作的:

func ReadWrite() bool {
file.Open("file")
// 做一些工作
if failureX {
file.Close()
return false
} if failureY {
file.Close()
return false
} file.Close()
return true
}

我们看到上面有很多重复的代码,Go的defer有效解决了这个问题。使用它后,不但代码量减少了很多,而且程序变得更优雅。在defer后指定的函数会在函数退出前调用。

func ReadWrite() bool {
file.Open("file")
defer file.Close()
if failureX {
return false
}
if failureY {
return false
}
return true
}

如果有很多调用defer,那么defer是采用后进先出模式,所以如下代码会输出4 3 2 1 0

for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}

defer 给我的第一印象就是,类似Java中的

try {

}finally {

}

我目前的理解就是,在函数块中使用defer,就是函数对应的有一个栈空间,先进后出。需要函数结束后调用栈,来出发defer操作。

如果,一个对象的创建,很消耗内存,需要及时关闭,defer无法像try finnaly哪样准确。

  1. package main
  2. import "fmt"
  3. import "time"
  4. type User struct {
  5. username string
  6. }
  7. func (this *User) Close() {
  8. fmt.Println(this.username, "Closed !!!")
  9. }
  10. func main() {
  11. u1 := &User{"jack"}
  12. defer u1.Close()
  13. u2 := &User{"lily"}
  14. defer u2.Close()
  15. time.Sleep(10 * time.Second)
  16. fmt.Println("Done !")
  17. }
  18. [vicky@localhost goroutine]$

[vicky@localhost goroutine]$ go run deferTest1.go
Done !
lily Closed !!!
jack Closed !!!
[vicky@localhost goroutine]$

实际上,线程Sleep的10秒,u1,和u2早就可以Close()了,但却需要依赖main()函数的结束,才能defer执行。

那么尝试给defer添加内部代码区:

  1. package main
  2. import "fmt"
  3. import "time"
  4. type User struct {
  5. username string
  6. }
  7. func (this *User) Close() {
  8. fmt.Println(this.username, "Closed !!!")
  9. }
  10. func main() {
  11. {
  12. // 即便加了代码快范围,依旧也要主函数体结束才执行defer
  13. u1 := &User{"jack"}
  14. defer u1.Close()
  15. }
  16. u2 := &User{"lily"}
  17. defer u2.Close()
  18. time.Sleep(10 * time.Second)
  19. fmt.Println("Done !")
  20. }

Done !
lily Closed !!!
jack Closed !!!
[vicky@localhost goroutine]$

依旧defer的执行在Done!后。那么如何才能达到try finally 哪样准确的Close呢?

  1. package main
  2. import "fmt"
  3. import "time"
  4. type User struct {
  5. username string
  6. }
  7. func (this *User) Close() {
  8. fmt.Println(this.username, "Closed !!!")
  9. }
  10. func main() {
  11. u1 := &User{"jack"}
  12. f(u1) // 这样的方式,u1才会不依赖main函数的执行
  13. // 这样的方式,u2也不会依赖main函数的执行
  14. u2 := &User{"lily"}
  15. // m := func() {
  16. //         defer u2.Close()
  17. //         // u2 do somthing
  18. // }
  19. // m()<pre name="code" class="plain">        func() {
  20. defer u2.Close()
  21. // u2 do somthing
  22. }()</pre>        time.Sleep(10 * time.Second)        fmt.Println("Done !")}func f(u *User) {        defer u.Close()        // u1 do gomething}

[vicky@localhost goroutine]$ go run deferTest3.go
jack Closed !!!
lily Closed !!!
Done !

这样的使用方式,视乎不太合理,但却有存在的必要性。大多数情况下,可以用于 u1,u2  之类非常消耗内存,或者cpu,其后执行时间过程且没有太多关联的情况。既保留了defer的功能特性,也满足范围精确控制的条件!

GO语言中间的derfer的更多相关文章

  1. Go语言性能优化

    原文:http://bravenewgeek.com/so-you-wanna-go-fast/ 我曾经和很多聪明的人一起工作.我们很多人都对性能问题很痴迷,我们之前所做的是尝试逼近能够预期的(性能) ...

  2. C语言 · 高精度加法

    问题描述 输入两个整数a和b,输出这两个整数的和.a和b都不超过100位. 算法描述 由于a和b都比较大,所以不能直接使用语言中的标准数据类型来存储.对于这种问题,一般使用数组来处理. 定义一个数组A ...

  3. Windows server 2012 添加中文语言包(英文转为中文)(离线)

    Windows server 2012 添加中文语言包(英文转为中文)(离线) 相关资料: 公司环境:亚马孙aws虚拟机 英文版Windows2012 中文SQL Server2012安装包,需要安装 ...

  4. iOS开发系列--Swift语言

    概述 Swift是苹果2014年推出的全新的编程语言,它继承了C语言.ObjC的特性,且克服了C语言的兼容性问题.Swift发展过程中不仅保留了ObjC很多语法特性,它也借鉴了多种现代化语言的特点,在 ...

  5. C语言 · Anagrams问题

    问题描述 Anagrams指的是具有如下特性的两个单词:在这两个单词当中,每一个英文字母(不区分大小写)所出现的次数都是相同的.例如,"Unclear"和"Nuclear ...

  6. C语言 · 字符转对比

    问题描述 给定两个仅由大写字母或小写字母组成的字符串(长度介于1到10之间),它们之间的关系是以下4中情况之一: 1:两个字符串长度不等.比如 Beijing 和 Hebei 2:两个字符串不仅长度相 ...

  7. JAVA语言中的修饰符

    JAVA语言中的修饰符 -----------------------------------------------01--------------------------------------- ...

  8. Atitit 项目语言的选择 java c#.net  php??

    Atitit 项目语言的选择 java c#.net  php?? 1.1. 编程语言与技术,应该使用开放式的目前流行的语言趋势1 1.2. 从个人职业生涯考虑,java优先1 1.3. 从项目实际来 ...

  9. 【开源】简单4步搞定QQ登录,无需什么代码功底【无语言界限】

    说17号发超简单的教程就17号,qq核审通过后就封装了这个,现在放出来~~ 这个是我封装的一个开源项目:https://github.com/dunitian/LoTQQLogin ————————— ...

随机推荐

  1. springMVC配置freemarker

    这里呢,我首先来说明一下写该篇的目的. 我最近要用到freemarker因此研究了一下这个东西. 先来说说如何配置吧. 1.jar包.地址见下链接. http://pan.baidu.com/s/1j ...

  2. HttpClient的使用方法

    使用httpClient发送请求.接收响应很简单.一般需要以下几个步骤. 第一:创建HttpClient对象: 第二:创建请求方法的实例,并指定请求URL.如果要发送GET请求,创建HttpGet对象 ...

  3. API判断网站IP地址,国家区域

    直接访问http://api.wipmania.com/jsonp 还有经纬度

  4. drawer principle in Combinatorics

    Problem 1: Given an array of real number with length (n2 + 1) A: a1,  a2, ... , an2+1. Prove that th ...

  5. HDU(2485),最小割最大流

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=2485 Destroying the bus stations Time Limit: 40 ...

  6. spoj LCMSUM sigma(lcm(i,n));

    Problem code: LCMSUM Given n, calculate the sum LCM(1,n) + LCM(2,n) + .. + LCM(n,n), where LCM(i,n) ...

  7. 华东交通大学2016年ACM“双基”程序设计竞赛 1003

    Problem Description 风雨漂泊异乡路, 浮萍凄清落叶飞. 游子寻根满愁绪,一朝故土热泪归.Hey ecjtuer! 刚刚学习了二叉树的知识,现在来考察一下..给你一个深度为h的满二叉 ...

  8. COGS502. 长路上的灯

    502. 长路上的灯 ☆   输入文件:light.in   输出文件:light.out   简单对比时间限制:1 s   内存限制:128 MB [题目描述] 在一条无限长的路上,有一排无限长的路 ...

  9. java初始化笔记

    构造器初始化static块与非static块区别:对象创建时都做块的初始化,非static块仅在实例创建时初始化,static块在类被第一次加载时初始化数组初始化注意点:1.数组定义时最好在定义的同时 ...

  10. 异常详细信息: System.Web.Hosting.HostingEnvironmentException: 访问 IIS 元数据库失败 解决方法

    访问IIS元数据库失败 同理,给操作系统的新建用户赋予IIS操作权限同样可以采用该命令来处理 说明: 执行当前 Web 请求期间,出现未处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错 ...