A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because the surrounding function executed a return statement, reached the end of its function body, or because the corresponding goroutine is panicking.

defer语句会在以下几种情况下被执行:

a. 函数执行return语句
b. 执行到函数体结尾
c. goroutine panic之前
 

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. That is, if the surrounding function returns through an explicit return statement, deferred functions are executed after any result parameters are set by that return statement but before the function returns to its caller. If a deferred function value evaluates to nil, execution panics when the function is invoked, not when the "defer" statement is executed.

每次执行defer语句时,会将其定义的函数和参数保存在一个栈中,但是定义的函数并不会被执行。但是,在外层函数退出之前,defer函数会按照定义的顺序逆序执行。如果外层函数通过显示return语句返回,则defer定义的函数是在设置结果参数之后,返回调用方之前执行。如果defer要执行的函数为nil,则会在定义的函数调用时产生panic,而不是defer语句执行时。

 

1. defer原理分析

a. 多个defer执行顺序

当一个函数中存在多个defer语句时,函数返回之前会按照defer定义的顺序逆序执行,也就是说最先注册的defer函数最后执行。

b. defer语句执行时拷贝时机

当defer语句执行时,会将当前时刻的函数值和函数参数进行注册。注册完成之后再次修改函数值和函数参数将不会生效。

c. return & defer

return x :返回值 = x   +   RET指令

defer 原理 :返回值 = x + defer语句 + RET指令

d. defer & 闭包

func main() {
  x := 1
  defer func() {
    fmt.Println(x)      // 2
  }()
  x++
}

上例中的 func()是一个闭包,闭包的变量本质是对上层变量的引用。

type Closure struct {

  F func()

  x *int

}

相比于直接调用函数,延迟调用需要花费更大的代价。这其中包括注册、调用等操作,还有额外的缓存开销。

对于性能要求高且压力大的算法,应该尽量避免延迟调用。

defer综合的更多相关文章

  1. 前端面试题集锦及答案解析--HTML、 HTTP、web综合问题

    前端需要注意哪些SEO 合理的title.description.keywords:搜索对着三项的权重逐个减小,title值强调重点即可,重要关键词出现不要超过2次,而且要靠前,不同页面title要有 ...

  2. 浏览器环境下JavaScript脚本加载与执行探析之defer与async特性

    defer和async特性相信是很多JavaScript开发者"熟悉而又不熟悉"的两个特性,从字面上来看,二者的功能很好理解,分别是"延迟脚本"和"异 ...

  3. golang基础--细说defer

    defer 匿名函数特性 执行方式类似其它语言中的析构函数,在函数体执行结束后按照调用顺序的相反顺序逐个执行 //执行顺序相反 package main import "fmt" ...

  4. golang学习之defer

    golang中的defer通常用于执行一些资源释放性操作,比如open/close.connect/disconnect.lock/unlock等,对defer理解主要记住以下三点: 1.defer ...

  5. AEAI DP V3.6.0 升级说明,开源综合应用开发平台

    AEAI DP综合应用开发平台是一款扩展开发工具,专门用于开发MIS类的Java Web应用,本次发版的AEAI DP_v3.6.0版本为AEAI DP _v3.5.0版本的升级版本,该产品现已开源并 ...

  6. H5+JS+CSS3 综合应用

    慕课网新教程H5+JS+CSS3 实现的七夕言情主题效果已经出炉了 从设计到实现到录制与编写用了快1个月的时间,说真的这个案例是慕课定制的,我之前也没有系统的做过这样的一个效果,在实现的时候自己也重新 ...

  7. 浅谈Angular的 $q, defer, promise

    浅谈Angular的 $q, defer, promise 时间 2016-01-13 00:28:00  博客园-原创精华区 原文  http://www.cnblogs.com/big-snow/ ...

  8. javascript的defer和async的区别。

    我们常用的script标签,有两个和性能.js文件下载执行相关的属性:defer和async defer的含义[摘自https://developer.mozilla.org/En/HTML/Elem ...

  9. script标签中defer和async属性的区别

    这篇文章来源于JS高级程序设计第三版中关于script标签的介绍,结合查阅的资料写下的学习笔记. 向html页面中插入javascript代码的主要方法就是通过script标签.其中包括两种形式,第一 ...

随机推荐

  1. centos7升级openssh8.7&openssl1.1.1l脚本

    脚本下载地址或首页联系本人获取 https://files.cnblogs.com/files/blogs/705493/update_ssh.sh 需搭配openssh8.7和openssl1.1. ...

  2. Oracle在存储过程中建表、建索引权限不足

    修改存储过程,在存储过程名称后面添加 Authid Current_User 后执行通过. CREATE OR REPLACE PROCEDURE p_test Authid Current_User ...

  3. java中自己常用到的工具类-压缩解压zip文件

    package com.ricoh.rapp.ezcx.admintoolweb.util; import java.io.File; import java.io.FileInputStream; ...

  4. file_put_contents利用技巧(php://filter协议)

    Round 1 <?php $content = '<?php exit; ?>'; $content .= $_POST['txt']; file_put_contents($_P ...

  5. swap分区扩展的三种方法

    redhat linux swap分区扩展的三种方法 2016-12-26 11:41:08 分类: LINUX 原文地址:redhat linux swap分区扩展的三种方法 作者:quanshen ...

  6. VT 入门番外篇——初识 VT

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  7. Flutter查漏补缺1

    Flutter 基础知识查漏补缺 Hot reload原理 热重载分为这几个步骤 扫描项目改动:检查是否有新增,删除或者改动,直到找到上次编译后发生改变的dart代码 增量编译:找到改变的dart代码 ...

  8. 对redis数据库的初步认识

    由于之前接触的都是关系型数据库,对于非关系型数据库总是不了解,趁着外出做项目的机会,正好初步认识了redis数据库 redis分为存储分为几个存储的数据类型 string类型,hash类型,list链 ...

  9. JDBC-Druid增删改查

    由于刚学完JDBC,所以来小练一下,通过Druid实现对数据库的增删改查操作 (现在是真正简单的纯数据库操作,等我学过前端,再做一个比较具体的!) •数据库 新建一个数据库tb,创建brand表,有主 ...

  10. Dubbo 使用过程中都遇到了些什么问题?

    在注册中心找不到对应的服务,检查 service 实现类是否添加了@service 注解 无法连接到注册中心,检查配置文件中的对应的测试 ip 是否正确