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. 【安卓基础】WebView开发优化基础

    最近工作很忙,不仅要抽空进行管理,还有开发任务在身,幸好有一些规划进行指导,所以还能顺利解决问题.在管理和技术上面,我认为技术是硬实力,管理是软实力,自己需要多点时间花在技术上. 回归正题,在项目中的 ...

  2. STL练习板子题(c++11警告)

    第一题 词典 总时间限制: 3000ms 内存限制: 65536kB 描述 你旅游到了一个国外的城市.那里的人们说的外国语言你不能理解.不过幸运的是,你有一本词典可以帮助你. 输入 首先输入一个词典, ...

  3. ckeditor粘贴word文档图片的思路

    由于工作需要必须将word文档内容粘贴到编辑器中使用 但发现word中的图片粘贴后变成了file:///xxxx.jpg这种内容,如果上传到服务器后其他人也访问不了,网上找了很多编辑器发现没有一个能直 ...

  4. leetcode解题报告(6):Remove Duplicates from Sorted List

    描述 Given a sorted linked list, delete all duplicates such that each element appear only once. For ex ...

  5. Java操作文件那点事

    刚开始学Java时候,一直搞不懂Java里面的io关系,在网上找了很多大多都是给个结构图草草描述也看的不是很懂.而且没有结合到java7 的最新技术,所以自己结合API来整理一下,有错的话请指正,也希 ...

  6. Irrlicht引擎剖析二

  7. final关键字的理解

    final :最终作为一个修饰符 1.可以修饰类,函数,变量: 2.被final修饰的类不可以被继承: 3.被final修饰的方法不可以被复写: 4.被final修饰的变量是一个常量,只能赋值一次,既 ...

  8. Maven的概述和基础(学习整理)

    1. Maven是啥 Maven是一个项目管理工具,包含了一个项目对象模型(POM),一组标准集合,一个项目生命周期(Lifecycle),一个依赖管理系统,和用来运行定义在生命周期阶段中的插件目标的 ...

  9. 学号20175313 《实现Linux下Sort -t : -k 2功能》第十二周

    目录 一.题目要求 二.题目理解 三.设计思路 四.代码实现 五.代码链接 六.运行结果截图 七.参考资料 一.题目要求 实现Linux下Sort -t : -k 2的功能 二.题目理解 -t 分隔符 ...

  10. NMS(非极大值抑制)实现

    1.IOU计算 设两个边界框分别为A,B.A的坐标为Ax1,Ax2,Ay1,Ay2,且Ax1 < Ax2,Ay1 < Ay2.B和A类似. 则IOU为A∩B除以A∪B. 当两个边界框有重叠 ...