美文网首页go 语言学习
Go语言defer关键字

Go语言defer关键字

作者: 楠小忎 | 来源:发表于2018-08-02 16:09 被阅读5次

Go语言defer关键字

  • defer关键字用于延缓函数的执行
  • 只需要在调用普通函数或方法前加上关键字defer,就完成了defer所需要的语法。当defer语句被执行时,跟在defer后面的函数就会被延迟执行。直到包含该defer语句的函数执行完毕时,defer后面的函数才会被执行,不论包含defer语句的函数是通过return正常结束,还是由于panic导致的异常结束。你可以在一个函数中执行多条defer语句,它们的执行顺序与声明顺序相反。
  • defer语句经常被用于处理成对的操作,如打开、关闭、连接、断开连接、加锁、释放锁。通过defer机制,不论函数逻辑多复杂,都能保证在任何执行路径下,资源被释放。释放资源的defer应该直接跟在请求资源的语句后。
  • 对文件的操作的例子
package ioutil
func ReadFile(filename string) ([]byte, error) {
    f, err := os.Open(filename)
    if err != nil  {
        return nil, err
    }
    defer f.Close()
    return ReadAll(f)
}
  • 处理互斥锁的例子
var mu sync.Mutex
var m = make(map[string]int)
func lookup(key string) int {
    mu.Lock()
    defer mu.Ulock()
    return m[key]
}
  • 调试复杂程序时,defer机制也常被用于记录何时进入和退出函数。
  • 下例中的bigSlowOperation函数,直接调用trace记录函数的被调情况。bigSlowOperation函数被调时,trace会返回一个函数值,该函数值会在bigSlowOperation退出时被调用。通过这种方式,我们可以只通过一条语句控制函数的入口和所有的出口,甚至可以记录函数的运行时间,如例子中的start。
func bigSlowOperation() {
    defer trace("bigSlowOPeration")()
    extra parentheses
    //lot of works
    time.Sleep(10 * time.Second) //simulate slow
    operation by sleeping
}

func trace(msg string) func() {
    start := time.Now()
    log.Printf("enter %s", msg)
    return func() {
        log.Printf("exit %s (%s)", msg, tie.Since(start))
    }
}
  • defer语句中的函数会在return语句更新返回值变量后再执行,又因为在函数定义的匿名函数可以访问该函数包括返回值变量内的所有变量,所以,对匿名函数采用defer机制,可以使其观察函数的返回值
func double(x int) (result int) {
    defer func() {fmt.Printf("double(%d) = %d\n", x, result)}()
    return x + x
}

_ = double(4) //"8"
  • 被延迟执行的匿名函数甚至可以修改函数返回给调用者的返回值
func triple(x int) (result int) {
    defer func() {return += x}()
    return double(x)
}

fmt.Println(triple(4))
  • 在循环体中的defer语句特别需要注意。因为只有在函数执行完毕后,这些被延迟的函数才会执行。

  • 下面的代码会导致系统的文件描述符耗尽,因为所有文件都被处理之前,没有文件会被关闭

for _, filename := range filenames {
    f, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer f.Close()
    descriptors
    //...
}
  • 一种方法是将循环体中的defer语句移至另外一个函数。在每次循环时,调用这个函数
for _, filename := range filenames {
    if err := doFile(filename); err != nil {
        return err
    }
}

func doFile(filename string) error {
    f, err := os.Open(filename)
    if err != nil {
        return err
    }
    
    defer f.Close()
    ...
}

相关文章

  • Go语言学习进度(7)

    1.GO语言关键字Interface 举例说明: 2.GO语言关键字defer

  • Go语言defer关键字

    Go语言defer关键字 defer关键字用于延缓函数的执行 只需要在调用普通函数或方法前加上关键字defer,就...

  • Go语言 defer

    参考文章:深入理解Go语言 defer用于资源的释放,会在函数返回之前进行调用 defer关键字的实现跟go关键字...

  • Golang学习笔记-defer关键字学习

    defer学习 很多现代的变成语言中都会有defer关键字,Go语言的defer会在当前函数或是方法返回之前执行传...

  • Go语言基础(二)

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

  • Go 语言基础——错误处理

    学习目标 掌握错误处理 掌握自定义错误处理 掌握defer关键字的使用 错误处理 GO没有异常处理机制 Go语言引...

  • GO中defer关键字

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

  • Go语言——defer

    Go语言——defer defer操作类似stack,FILO先进后出。 与return一直使用的时候,需要注意顺...

  • go语言——defer

    defer

  • golang语言defer特性详解.md

    [TOC] golang语言defer特性详解 defer语句是go语言提供的一种用于注册延迟调用的机制,它可以让...

网友评论

    本文标题:Go语言defer关键字

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