美文网首页
『go成长之路』 defer 作用、典型用法以及多个defer调

『go成长之路』 defer 作用、典型用法以及多个defer调

作者: 亦一银河 | 来源:发表于2021-08-11 01:31 被阅读0次

预习内容

  • 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可以修改函数最终返回值。

相关文章

  • 『go成长之路』 defer 作用、典型用法以及多个defer调

    预习内容 defer 的作用有哪些? 多个 defer 的执行顺序是怎样的? defer,return,函数返回值...

  • goLang异常处理

    defer defer是go提供的一种资源处理的方式。defer的用法遵循3个原则在defer表达式被运算的同时,...

  • go语言的defer语句

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

  • Go语言基础(二)

    目录 关键字 defer go的defer用法范例[https://www.jianshu.com/p/7ada9...

  • 异常

    1、error接口 2、defer 你可以在Go函数中添加多个defer语句,当函数执行到最后时,这些defer语...

  • GO中defer关键字

    defer关键字在go中用于return之前执行,在golang官方文档中有说明。defer的用法类似java中的...

  • go defer用法

    defer 通常用于 open/close, connect/disconnect, lock/unlock 等这...

  • Go Defer

    Go Defer 如果函数里面有多条defer指令,他们的执行顺序是反序,即后定义的defer先执行。 defer...

  • Go函数-延迟调用(三)

    在go语言里,defer可是实现延迟函数调用。语句defer向当前函数注册稍后执行的函数调用。这些调用被称做延迟调...

  • 深入理解 Go-Defer的机制

    defer 的作用和执行时机 go 的 defer 语句是用来延迟执行函数的,而且延迟发生在调用函数 return...

网友评论

      本文标题:『go成长之路』 defer 作用、典型用法以及多个defer调

      本文链接:https://www.haomeiwen.com/subject/xkjqbltx.html