『go成长之路』 defer 作用、典型用法以及多个defer调用顺序,附加defer避坑点,拿来吧你

预习内容

  • defer 的作用有哪些?
  • 多个 defer 的执行顺序是怎样的?
  • defer,return,函数返回值 三者之间的执行顺序

defer的作用

go中的defer延迟函数,一般是用于释放资源或者收尾工作

由于defer是具有延迟特性且执行动作是在函数return之后,因此作为资源释放作用再好不过。

  • 典型例子:释放锁、关闭文件、关闭链接
// 释放锁
func getValue() {
  s.Lock()
  defer s.Unlock()
  ...
}

// 关闭文件
func read() {
  f, err := os.OpenFile("filename", os.O_RDWR, os.ModePerm)
    defer f.Close()
  ...
}

// 关闭链接
func connect() {
  resp, err := grequests.Get(s.cfg.GateApiCrossMarginUrl, nil)
    defer resp.Close()
  ...
}

// 收尾工作,defer 同时也是函数,可以做很多收尾相关工作
func closeConnection() {
  ...
  defer func() {
    file.close()
    close(readChan)
  }
  ...
}
  • 还有作用就是捕获 panic,这个功能在defer里也是典型用法
func sendChan() {
  // 此处捕获 panic 进行 recover 防止程序崩溃
    defer func() {
    if ok := recover(); ok != nil {
        fmt.Println("recover")
    }
  }()
  // 向已经关闭的chan发送数据,此处会引起 panic
  dataChan <- "message"
  ...
}

defer 释放资源『避坑指南』

资源释放动作一定紧跟资源使用(打开、连接)语句,不然defer可能不会被执行到,导致内存泄露

// 关闭文件
func read() error {
  f1, err := os.OpenFile("filename", os.O_RDWR, os.ModePerm)
  if err != nil {
    return err
  }
  // 此时,defer还没执行到,提前return了,无效defer导致内存泄露
    defer f1.Close()
  
  // 正确用法,紧跟资源使用语句
  f2, err := os.OpenFile("filename", os.O_RDWR, os.ModePerm)
  defer f2.Close()
  if err != nil {
    return err
  }
}

defer 的调用顺序

墙裂建议不要先看后面的介绍做下面的题目,此处先跳过介绍defer调用顺序,看看下面比较典型的对defer顺序判断,你能看出来几个?

func deferFunc1(i int) (t int) {
    t = i
    defer func() {
        t += 1
    }()
    return t
}

func deferFunc2(i int) int {
    t := i
    defer func() {
        t += 1
    }()
    return t
}

func deferFunc3(i int) (t int) {
    defer func() {
        t += i
    }()
    return 1
}

func deferFunc4() (t int) {
    defer func(i int) {
        fmt.Println(i)
        fmt.Println(t)
    }(t)
  t = 0
    return 1
}

func ExecDeferFunc() {
  // 猜猜下面输出的内容和顺序
    fmt.Println(deferFunc1(1)) 
    fmt.Println(deferFunc2(1))
    fmt.Println(deferFunc3(1))
    deferFunc4()
}

猜想结果可能是:2,2,1,0,0 或者 2,2,1,1,1 ?

估计比较模糊的地方应该是函数返回值 和 return value(函数返回值)关系不明确,还有就是对defer产生作用的时机不明确

正文开始!

再次强调defer是延迟函数,执行动作在return之后,defer相当于是将执行动作压入栈中,越是后面的defer越是先执行,执行顺序是LIFO(后进先出)

特别指出:有函数返回值的则return将结果写入返回值,defer进行收尾,可以看做 return最先执行,然后return将结果存入返回值,最后defer执行

那么基于刚刚的介绍再回头去看得到的『实际结果是:2,1,2,0,1』

复习内容

  • defer 用于资源释放和收尾工作
  • 多个 defer 调用顺序是 LIFO(后入先出),defer后的操作可以理解为压入栈中
  • defer,return,return value(函数返回值) 执行顺序:首先return,其次return value,最后defer。defer可以修改函数最终返回值。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • 用法介绍: defer是Go语言中的延迟执行语句,用来添加函数结束时执行的代码,常用于释放某些已分配的资源、关闭数...
    也许会了阅读 943评论 0 0
  • defer语句是Go中一个非常有用的特性,可以将一个方法延迟到包裹该方法的方法返回时执行,在实际应用中,defer...
    simpleapples阅读 39,956评论 2 34
  • defer 的作用和执行时机 go 的 defer 语句是用来延迟执行函数的,而且延迟发生在调用函数 return...
    云爬虫技术研究笔记阅读 1,904评论 0 2
  • Go语言defer关键字 defer关键字用于延缓函数的执行 只需要在调用普通函数或方法前加上关键字defer,就...
    楠小忎阅读 3,015评论 1 0
  • GO 中 defer的实现原理 我们来回顾一下上次的分享,分享了关于 通道的一些知识点 分享了 GO 中通道是什么...
    阿兵云原生阅读 825评论 0 5