美文网首页
一文了解defer操作

一文了解defer操作

作者: 风云风雨 | 来源:发表于2021-02-26 09:58 被阅读0次

什么是defer?

defer是go语言提供的一种用于注册延迟调用的机制,让函数或语句可以在当前函数执行完毕后(包括通过return正常结束或panic导致的异常结束)执行。

适用场景:

  • 打开/关闭连接
  • 加锁/释放锁
  • 打开/关闭文件等

defer在一些需要回收资源的场景非常有用,可以很方便在函数结束前做一些清理工作。

为什么要用defer?

在编程过程中,经常需要打开一些资源,比如数据库、文件、锁等,这些资源都需要用完释放,否则会造成内存泄漏。

当然在使用过程中,可以在函数结束时显式关闭资源,但是如果在打开和关闭资源之间如果发生了panic会退出函数,导致关闭资源没有被执行。因为这样一颗语法糖,减少了很多资源泄漏的情况。

defer底层

官方对defer的解释:

Each time a “defer” statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked. Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred. If a deferred function value evaluates to nil, execution panics when the function is invoked, not when the “defer” statement is executed.

每次defer语句执行时,会把函数“压栈”,函数的参数会被拷贝下来,当外层函数退出时,defer函数按照定义的逆序执行,如果defer执行的函数为nil,那么会在最终调用函数产生panic。

这里有一道经典题:

func main() {
    a,b := 1,2
    defer cal("1",a,cal("10",a,b))
    a = 0
    defer cal("2",a,cal("20",a,b))
}

func cal(index string, a, b int) int {
    ret := a + b
    fmt.Println(index,a,b,ret)
    return ret
}

// Output:
10 1 2 3
20 0 2 2
2 0 2 2
1 1 3 4

这是遵循先入后出的原则,同时保留当前变量的值。

看看下面这道题:

func f1() (r int) {
    defer func() {
        r++
    }
    return 0
}

func f2() (r int) {
    t := 5
    defer func() {
        t = t + 5
    }
    return t
}

func f3() (r int) {
    defer func(r int) {
        r = r + 5
    }(r)
    return 1
}

// Output:
1
5
1

你能正确答对吗?

关键点在于理解这条语句:

return xxx

这条语句并不是一个原子命令,经过编译后,变成3条指令:

1、返回值=xxx
2、调用defer函数
3、空的return

那么我们来拆解上面3个函数。

func f1() (r int) {
    // 1、赋值
    r = 0
    // 2、闭包引用
    defer func() {
        r++
    }
    // 3、空的return
    return 0
}
// defer是闭包引用,所以返回值被修改,所以f1()返回1

func f2() (r int) {
    t := 5
    // 1、赋值
    r = t
    // 2、闭包引用,但没有修改r
    defer func() {
        t = t + 5
    }
    // 3、空的return
    return t
}
// 没涉及返回值r的操作,所以返回5

func f3() (r int) {
    // 1、赋值
    r = 1
    // 2、r作为参数传值,不会修改返回值的r
    defer func(r int) {
        r = r + 5
    }(r)
    // 3、空的return
    return 
}
// 第二步r是作为函数参数使用的,是一份复制,defer语句中的r和外面的r是两个变量,里面r的变化不会改变外面r,所以返回1.

相关文章

  • 一文了解defer操作

    什么是defer? defer是go语言提供的一种用于注册延迟调用的机制,让函数或语句可以在当前函数执行完毕后(包...

  • golang之panic/defer/recover

    defer 在函数返回之前, 调用defer函数的操作; 函数内可以有多个defered函数, 但是这些defer...

  • golang中defer执行时机与常见问题

    defer是什么? defer的用途 defer的执行时机 了解defer的执行时机首先要知道golang的ret...

  • go defer性能测试

    在学习中了解到defer相比没有使用defer会消耗部分时间,所以测试了下,使用与不使用defer的性能测试,通过...

  • Swift - defer 关键字

    defer常用于数据库操作中的打开关闭或我们要执行某些必要操作流程时候defer会在该当前声明的作用域结束时候执行...

  • Go语言——defer

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

  • go defer 的使用和陷阱

    前言 初学 go 的同学都应该了解 defer, defer 让人又爱又恨;当 defer 和 闭包结合在一起的时...

  • RxJava操作符简单总结

    引用自 Observables下面是常用的操作符列表:创建操作 Create, Defer, Empty/Nev...

  • 创建型操作符

    创建型操作符 create from just defer timer interval range repeat...

  • defer操作符

    defer() 是一个创建操作符,它会一直等待直到有观察者订阅它,才使用Observable工厂方法生成一个Obs...

网友评论

      本文标题:一文了解defer操作

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