Go实战

原址

生命不止,继续 go go go !!!

学习golang这么久了,还没看到类似传统的 try…catch…finally 这种异常捕捉方式。 
但是,Go中引入的Exception处理:defer, panic, recover。

那么今天跟大家分享一下golang中的defer。闲言少叙,看一下defer的作用:

Defer is used to ensure that a function call is performed later in a program’s execution, usually for purposes of cleanup. defer is often used where e.g. ensure and finally would be used in other languages.

defer的思想类似于C++中的析构函数,不过Go语言中“析构”的不是对象,而是函数,defer就是用来添加函数结束时执行的语句。注意这里强调的是添加,而不是指定,因为不同于C++中的析构函数是静态的,Go中的defer是动态的。

引自:http://www.cnblogs.com/ghj1976/archive/2013/02/11/2910114.html

说多无用,想来个开胃菜,看看如何使用:

  1. package main
  2. import 'fmt'
  3. func main() {
  4. defer goodbye()
  5. defer goodnight()
  6. fmt.Println('Hello world.')
  7. }
  8. func goodnight() {
  9. fmt.Println('GoodNight')
  10. }
  11. func goodbye() {
  12. fmt.Println('Goodbye')
  13. }
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

输出: 
Hello world. 
GoodNight 
Goodbye

看出什么了吗? 
**defer在函数结束之前执行 
多个defer的执行顺序: Multiple defers are stacked last-in first-out so that the most recently deferred function is run first.**

那么defer之前就return了呢?

package mainimport 'fmt'func main() {fmt.Println('Hello world.')returndefer goodbye()defer goodnight()}func goodnight() {fmt.Println('GoodNight')}func goodbye() {fmt.Println('Goodbye')}
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

输出: 
Hello world. 
defer是在return之前执行的

defer用于关闭文件

  1. package main
  2. import 'fmt'
  3. import 'os'
  4. func main() {
  5. f := createFile('/tmp/defer.txt')
  6. defer closeFile(f)
  7. writeFile(f)
  8. }
  9. func createFile(p string) *os.File {
  10. fmt.Println('creating')
  11. f, err := os.Create(p)
  12. if err != nil {
  13. panic(err)
  14. }
  15. return f
  16. }
  17. func writeFile(f *os.File) {
  18. fmt.Println('writing')
  19. fmt.Fprintln(f, 'data')
  20. }
  21. func closeFile(f *os.File) {
  22. fmt.Println('closing')
  23. f.Close()
  24. }
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

defer用于锁

func Divide(i int) error {mu.Lock()defer mu.Unlock()if i == 0 {return errors.New('Can't divide by zero!')}val /= ireturn nil}
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

defer中的坑儿

看下面的代码:

  1. package main
  2. import (
  3. 'fmt'
  4. )
  5. func main() {
  6. fmt.Println(f())
  7. fmt.Println(f1())
  8. fmt.Println(f2())
  9. }
  10. func f() (result int) {
  11. defer func() {
  12. result++
  13. }()
  14. return 0
  15. }
  16. func f1() (r int) {
  17. t := 5
  18. defer func() {
  19. t = t + 5
  20. }()
  21. return t
  22. }
  23. func f2() (r int) {
  24. defer func(r int) {
  25. r = r + 5
  26. }(r)
  27. return 1
  28. }
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

输出: 


1

要使用defer时不踩坑,最重要的一点就是要明白,return xxx这一条语句并不是一条原子指令! 
函数返回的过程是这样的:先给返回值赋值,然后调用defer表达式,最后才是返回到调用函数中。 
defer表达式可能会在设置函数返回值之后,在返回到调用函数之前,修改返回值,使最终的函数返回值与你想象的不一致。

(0)

相关推荐

  • Go 切片传递的隐藏危机

    提出疑问 在Go的源码库或者其他开源项目中,会发现有些函数在需要用到切片入参时,它采用是指向切片类型的指针,而非切片类型.这里未免会产生疑问:切片底层不就是指针指向底层数组数据吗,为何不直接传递切片, ...

  • 回答我,停止 Goroutine 有几种方法?

    大家好,我是煎鱼. 协程(goroutine)作为 Go 语言的扛把子,经常在各种 Go 工程项目中频繁露面,甚至有人会为了用 goroutine 而强行用他. 在 Go 工程师的面试中,也绕不开他, ...

  • 经方抓独法:领会实战抓独法!(附​:葛根汤抓独医案)

    一. 抓独法的特点 1.抓独法源流 今天我们讲抓独法.我们研究伤寒论有五法,有标本法,有聚类法,有平脉法,有截断法,还有我们的抓独法.抓独法呢,它是有源流的,在伤寒论的平脉法就讲到了."邪不 ...

  • 精集体站街:半路经典实战7类图形

    深山老牛 楼主 2019-05-10 08:31 最近很多朋友对于个股该低吸还是追高混淆,前面老牛把自己低吸的手法全部公布给了大家,以后就重点讲讲半路追涨做首板的一些方法.便于区分和选股. 以下,是我 ...

  • 实战训练!

    在采用双盲测试的条件下任意选择一只历史股票,对其做交易训练. 缠论选股操作的条件是尽可能在一个大级别的切入点位置进场,并且在大级别上没有出现终止信号之前,保持交易节奏. 不管你是有缠论基础还是新接触缠 ...

  • 四物汤实战篇!(加减脏腑病妇科病)

    一.四物汤加减脏腑病 1 血虚腹痛.微汗恶风.加官桂(七分).倍芍药. 2 嗽痰.加桑白皮.杏仁.麻黄.贝母( 各等分). 3 大便秘.加桃仁.大黄.麻仁.枳壳(减半余各等分). 4 血虚头眩.加天麻 ...

  • 欧赛斯超级品牌引擎背后的思想、方法及实战拆解(5)

    欧赛斯 品牌超级引擎™ 关注 前言:过去的品牌是一个Logo.一句广告语.一幅画.一支广告片,品牌仅仅是品牌表现,品牌那时还是是广告公司的事情:而今天的品牌是一个点.线.面.体构成的一个引擎化体系.品 ...

  • 学霸的考场作文实战示例:高考作文如何开头与结尾

    俗谚:编筐编篓,重在收口.写文章,常常是头难起,尾难收. 评卷时,开头结尾也往往是评卷人的聚焦点,基础等级和发展等级的许多点都可以从开头结尾看出来. 关于开头结尾的要求,古人有形象而精辟的说法,曰&q ...

  • 别再去买那些垃圾股了,每周2次主升浪不香吗?硬核实战技巧分享

    别再去买那些垃圾股了,每周2次主升浪不香吗?硬核实战技巧分享

  • 圆运动的实战古方总结

    天 物 太 极 相 感 朱熹有一句话"人人有一太极,物物有一太极."吴瑭把它推导到药物具体部位的升降:"盖芦主生,干与枝叶主长,花主化,子主收,根主藏,木也:草则收藏皆在 ...

  • 刘渡舟:经方实战乙肝16方证

    乙型病毒性肝炎简称"乙型肝炎",是由乙型肝炎病毒引起的肝脏炎性损害,是我国当前最常见的一种传染病.其传播途径复杂,具有病程较长.缠绵难愈的特点,同时也是肝硬化.肝癌等的重要发病基础 ...

  • 实战笔记:四年口腔溃疡,用补肾的方子治好了,请你抽空学一学

    (本文仅供学习.参考,不能替代医嘱和处方.文中所述配伍.方剂,必须在中医师当面辨证指导下来借鉴.应用,切勿盲目尝试.) 本文理论依据:<中医方剂学>.<中医病因病机学> 你好, ...