defer是Go语言中的延迟执行语句,用来添加函数结束时执行的代码,常用于释放某些已分配的资源、关闭数据库连接、断开socket连接、解锁一个加锁的资源。Go语言机制担保一定会执行defer语句中的代码。其它语言中也有类似的机制,比如Java、C#语言里的finally语句,C++语言里的析构函数(Destructor)可以起类似的作用,C++语言机制担保在对象被销毁前一定会执行析构函数中的代码。C++中的析构函数析构的是对象,Go中的defer析构的是函数。

一、defer语句执行时机

defer语句在函数返回之前 或者 函数中 return语句(return语句可能调用另一个函数) 之后执行。示例代码:

package main

import (
"fmt"
) func main() {
fmt.Println(deferReturn())
} func deferReturn() (ret int) {
defer func() {
ret++
}()
return 10
}

上述代码打印出来的值是:11。 defer语句 匿名函数中的“ret++” 对返回值 10 加 1 变成了 11。再来看一个defer语句出现在return语句之后的代码:

func returnDefer() (ret int) {
return 0
defer func() {
ret++
ret++
}()
return 1
}

上述returnDefer函数的返回值是:0。原因是defer语句还没有添加上代码执行到"return 0"函数就返回了,因此defer语句就没有执行。

二、多个defer语句的执行顺序是逆序执行

当出现多条 defer 语句时以逆序执行(类似栈,即后进先出)。示例代码:

func deferSample() {
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
}

上述代码将会输出:4 3 2 1 0

三、defer与panic

1、在panic语句后面的defer语句不被执行

示例代码:

func panicDefer() {
panic("panic")
defer fmt.Println("defer after panic")
}

上述代码的输出如下:

panic: panic

goroutine 1 [running]:
main.panicDefer()
    E:/godemo/testdefer.go:17 +0x39
main.main()
    E:/godemo/testdefer.go:13 +0x20

Process finished with exit code 2

可以看到 defer 语句没有执行。

2、在panic语句前的defer语句会被执行

示例代码:

func deferPanic() {
defer fmt.Println("defer before panic")
panic("panic")
}

上述代码的输出如下:

defer before panic
panic: panic

goroutine 1 [running]:
main.deferPanic()
    E:/godemo/testdefer.go:19 +0x95
main.main()
    E:/godemo/testdefer.go:14 +0x20

Process finished with exit code 2

defer 语句输出了内容。

Go中的panic类似其它语言中的抛出异常,panic后面的代码不再执行(panic语句前面的defer语句会被执行)。

四、return 的实现逻辑

1、第一步给返回值赋值(若是有名返回值直接赋值,匿名返回值 则 先声明再 赋值) ;
2、第二步调用RET返回指令并传入返回值,RET会检查是否存在defer语句,若存 在就先逆序插播 defer语句 ;
3、最后 RET 携带返回值退出函数 。

可以看出 , return 不是一个原子操作,函数返回值与 RET 返回值并不一定一致。

五、defer、 return、返回值三者顺序

defer、 return、返回值 三者的执行顺序是 : return 最先给返回值赋值;接着 defer 开始执行一些收尾工作;最后 RET 指令携带返回值退出函数。

Go语言中defer语句使用小结的更多相关文章

  1. C语言中if语句

    C语言if语句后面的表达式 C语言中if关键字之后(即括号内)均为表达式. 该表达式通常是逻辑表达式或关系表达式,但也可以是其它表达式,如赋值表达式等,甚至也可以是一个变量,这些变量的值都换算成了逻辑 ...

  2. C语言中while语句里使用scanf的技巧

    今天友人和我讨论了一段代码,是HDU的OJ上一道题目的解,代码如下 #include<stdio.h> { int a,b; while(~scanf("%d%d",& ...

  3. C语言中while 语句

    while的执行顺序 while 循环的执行顺序非常简单,它的格式是: while (表达式) { 语句: } 概念:当表达式为真,则执行下面的语句:语句执行完之后再判断表达式是否为真,如果为真,再次 ...

  4. c语言中的switch case语句

    switch--case语句中,switch后面跟一个变量,这个变量不可以是字符数组,字符指针,字符串数组,浮点型(实型).它可以是整型,字符型(在本质上也是整型).所以这导致case后面的常量表达式 ...

  5. Go语言中的defer

    可以用作一些资源的释放. 1.在一个函数内的defer执行顺序是先写的后执行,后写的先执行(遵循栈结构) func DeferTest1(){ defer fmt.Println("我是 d ...

  6. C/C++语言中const的用法

    1. const 在C和C++中的区别     C++中的const正常情况下是看成编译期的常量,编译器并不为const分配空间,只是在编译的时候将期值保存在名字表中,并在适当的时候折合在代码中. 所 ...

  7. golang学习 ---defer语句

    golang语言defer特性详解 defer语句是go语言提供的一种用于注册延迟调用的机制,它可以让函数在当前函数执行完毕后执行,是go语言中一种很有用的特性.由于它使用起来简单又方便,所以深得go ...

  8. C语言中,头文件和源文件的关系(转)

    简单的说其实要理解C文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程: 1.预处理阶段 2.词法与语法分析阶段 3.编译阶段,首先编译成纯汇编语句, ...

  9. C 语言中 setjmp 和 longjmp

    在 C 语言中,我们不能使用 goto 语句来跳转到另一个函数中的某个 label 处:但提供了两个函数——setjmp 和 longjmp来完成这种类型的分支跳转.后面我们会看到这两个函数在处理异常 ...

随机推荐

  1. GET 和 POST is so different

    .原理区别 一般我们在浏览器输入一个网址访问网站都是GET请求;再FORM表单中,可以通过设置Method指定提交方式为GET或者POST提交方式,默认为GET提交方式. HTTP定义了与服务器交互的 ...

  2. mysql 数据库练习题

    前面学习了MySQL的语句的基本用法,这里就开始做一些MySQL练习,这套题目一共45题,属于比较简单的,初学先试着做这个. 参考链接:https://www.cnblogs.com/SJP666/p ...

  3. stl常数测试

    如图: 数组的常数约为9.

  4. linux下core dump--转载

    原文链接:https://www.cnblogs.com/Anker/p/6079580.html   1.前言 一直在从事linux下后台开发,经常与core文件打交道.还记得刚开始从事linux下 ...

  5. [DK] 化学竞赛的大奖

    https://www.luogu.org/problemnew/show/T16502 无向图  缩点  树的直径  到直径两个端点的距离的较大值 #include <iostream> ...

  6. mac 安装docker

    下载地址: https://download.docker.com/mac/stable/Docker.dmg 从应用中找到 Docker 图标并点击运行.可能会询问 macOS 的登陆密码,输入即可 ...

  7. Android 之Activity启动模式(二)之 Intent的Flag属性

    首页博客链接关于我留言板 前面介绍了通过launchMode设置Activity的启动模式.本章接着介绍Activity的启动模式相关内容,讲解的内容是Intent与启动模式相关的Flag,以及and ...

  8. VS2010,VS2013 Datagridview控件的编辑列功能,弹窗界面被挤扁了

    搜了很久,没找到解决办法,在一个角落看到说要卸载Framework,实践后可以,发出来记一下. 解决办法: 发现自己电脑上多了Framework4.8,可能安装VS2013的时候自动安装的. 卸载了F ...

  9. IdentityServer4入门一

    这几天学习IdentityServer4,感觉内容有点乱,也可能自己水平有限吧.但为了巩固学习的内容,也打算自己理一下思路. 首先IdentityServer解决什么问题? 下图是我们的一个程序的组织 ...

  10. mysql服务器变量、缓存及索引

    服务器变量 注意:其中有些参数支持运行时修改,会立即生效:有些参数不支持,且只能通过修改配置文件,并重启服务器程序生效:有些参数作用域是全局的,且不可改变:有些可以为每个用户提供单独(会话)的设置. ...