后端技术总结

  • 首页
  • github
  • About Me
  1. 首页
  2. Golang
  3. 正文

Golang之defer

2021年4月21日 1003点热度 0人点赞 0条评论
内容纲要

背景

defer在golang中属于关键词,主要用于资源释放,会在函数返回之前被调用,但其中也包含了很多的坑。下面我们通过几个常见例子来进行相关的讲解。

例子

// e.g.1
func f1() (r int) {
    defer func() {
        r = r + 5
    }()
    return 1
}

// e.g.2
func f2() (r int) {
    t := 5
    defer func() {
        t = t + 5
    }()
    return t
}

// e.g.3
func f3() (r int) {
    t := 5
    defer func(r int) {
        r = r + 5
    }(r)
    return t
}

// e.g.4
func f4() {
    t := 5
    defer fmt.Println("t1 =", t)
    t = 4
    defer fmt.Println("t2 =", t)
}

我们先不直接说出其中运行的结果,我们都简单的针对上面的例子在心中计算一下,并想想是为什么,下面我在写出其中的结果.

原理讲解

以下为我们执行的实际结果

func main() {

    fmt.Println("f1() =", f1())
    fmt.Println("f2() =", f2())
    fmt.Println("f3() =", f3())
    f4()

    // Outputs:
    // f1() = 6
    // f2() = 5
    // f3() = 5
    // t2 = 4
    // t1 = 5

    return
}

上面的结果和你心中想到的是否一致?哈哈,如果一致的话相信你是懂defer的运行机制的,可以绕过本文了。有不懂或没弄对的地方的话,就继续往下看,我来一一给你讲解。

defer规则

我们来直接说一下defer的三个简单规则,详见官方文档

  • 规则1-延迟函数的参数在defer语句出现时就已经确定下来了
  • 规则2-延迟函数执行按后进先出顺序执行,即先出现的defer最后执行
  • 规则3-延迟函数可能操作主函数的具名返回值

针对规则1,意思是defer后面的函数一在定义完以后,如果函数有传入值,则在那一刻就把值给固定下来了,这个规则能很好的解释上面提到的f4(),打印的t1=5,t2=4

针对规则2,意思是说defer采用的是FILO(先进后出)的规则,用这个规则也能解释f4()里面的打印顺序问题,先打印t2再打印t1

针对规则3,意思是主函数可能有返回值,而这个defer后面的函数可能会影响到主函数的返回值,这里我们就使用规则3来对上面的另外三个例子进行一一说明,f1()里面return 1,哦,我再顺便说一个利于你理解记忆的小诀窍,在return的时候首先赋值,然后执行defer,最后返回,也就是先r=1,然后执行defer里面r = r + 5,最后才是返回的r,打印f1() = 6,解释通了吧?哈哈;f2()里面带有一点迷惑性,但是我们直接利用上面的规则拆分,return的时候是先执行的r = t,也就是r=5,而defer执行的操作只是对t操作,和r没有半毛钱的关系,这样打印f2() = 5也就能解释了;f3()里面同上面规则也一样,先赋值,但是有一点是defer里面函数通过值传递,在值传递的时候已经是进行了值的拷贝操作,并没有把返回的值给更改掉,或者换个思路,把f3()里面的defer函数r换成其他变量,也许一眼就看懂了;

小结

  • defer定义的延迟函数参数在defer语句出时就已经确定下来了
  • defer定义顺序与实际执行顺序相反
  • return不是原子操作,执行过程是: 保存返回值(若有)-->执行defer(若有)-->执行ret跳转申请资源后立即使用defer关闭资源是好习惯
标签: golang
最后更新:2021年8月15日

PingD

反思让我成长

点赞
< 上一篇
下一篇 >

文章评论

取消回复

PingD

反思让我成长

归档
  • 2023年1月
  • 2022年3月
  • 2022年1月
  • 2021年10月
  • 2021年8月
  • 2021年4月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2019年9月
  • 2019年7月
  • 2019年6月
  • 2019年4月
  • 2019年3月
最新 热点 随机
最新 热点 随机
断更了,不想写了 新路由2(newifi d1) 小白刷老毛子固件 2021年度总结 golang之从源码角度看slice的len和cap 基于chan实现的简易协程池及说明 订单超时方案(初稿)
Etcd raft 原理动画演示 Golang之defer 2021年度总结 could not launch process: decoding dwarf section info at offset 0x0: too short Go-如何将任意int或float转成string Golang之服务配置自动初始化
最近评论

COPYRIGHT © 2021 dpjeep.com. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

蜀ICP备18036663号-1