Go函数--defer语句

1 defer语句

该语句用于延迟调用指定的函数,它只能出现在函数或方法的内部,由defer 关键字以及针对某个函数的调用表达式组成。这里被调用的函数称为延迟函数。简单的示例如下

func outerFunc() {
    defer fmt.Println("函数执行结束前一刻才会被打印")
    fmt.Println("第一个被打印")
}

《代码说明》defer关键字后面是针对fmt.Println()函数的调用表达式。这里的outerFunc()称为外围函数

defer语句经常用于处理成对的操作,如打开和关闭、连接和断开连接、加锁和释放锁等。通过defer 机制,不论函数逻辑多复杂,都能保证在任何执行路径下,资源被释放和回收。释放资源的defer应该直接跟在请求资源的语句后。

<注意> defer后面必须是函数或方法的调用,不能是普通语句,否则会报 "expression in defer must be function call" 错误。

2 defer语句的特性

  • 当外围函数中的语句正常执行完毕时,只有其中所有的延迟函数都执行完毕,外围函数才会真正结束执行。
  • 当执行外围函数的return语句时,只有其中所有的延迟函数都执行完毕后,外围函数才会真正返回函数返回值。
  • 当外围函数中的代码引发运行时恐慌时(即执行了panic语句),只有其中所有的延迟函数都执行完毕后,该运行时恐慌才会真正扩散至调用函数。

正因为defer有这样的特性,所以它成为了执行释放资源或异常处理等收尾任务的首选。它有两个明显优势:

  • 对延迟函数的调用总会在外围函数执行结束前执行。
  • defer语句在外围函数体中的的位置不限,并且数量不限。

3 defer执行时机

在Go语言中,return语句在底层并不是原子操作,它分为给返回值赋值和执行RET指令(汇编指令)两步。而defer语句执行时机就在返回值赋值操作后,RET指令执行前。具体如下图所示:

 <说明> 可以看到,Go语言的return语句并不是RET汇编指令,它有两个步骤:1. 先更新返回值;2.再执行RET指令。

[参考] CALL和RET指令---汇编学习笔记

 示例:defer经典案例。

func f1() int {
    x := 5
    defer func() {
        x++   //修改的是变量x的值,不是返回值
    }()
    return x  //1.返回值赋值,即将x=5赋值给一个中间变量 2.执行defer语句 3.执行真正的R
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值