先看一下一段关于defer的解释, 引自《Go程序设计语言》

Syntactically, a defer statement is an ordinary function or method call prefixed by the keyword defer.
The function and argument expressions are evaluated when the statement is executed,
but the actual call is deferred until the function that contains the defer statement has finished, whether normally,
by executing a return statement or falling off the end, or abnormally, by panicking.
Any number of calls may be deferred; they are executed in the reverse of the order in which they were deferred.

大意是说:

  从语法上来说,defer 声明就像一个普通函数或方法,只是加了一个关键词为defer的前缀。当defer声明语句被程序执行时,函数和参数表达式被计算,但是直到包含defer声明的函数完成之后才被真正的调用,无论函数的结束方式是正常情况下执行return语句,还是异常情况下执行panic。可以声明多个defer语句,他们的按照声明的倒序执行。

吐槽一下自己先前的理解,以为程序执行时遇到defer语句时,跳过去,整个函数执行完毕再从下到上找到defer语句执行 =_=

很傻很天真,直到遇到下面的问题:

package main

import "fmt"

func main() {
defer pp(, f()) defer pp(, f()) } func pp(index int, r int) {
fmt.Println("defer", index, ": ", r)
} func f(index int) int {
fmt.Println(index)
return index
}

此处sleep 10 秒钟,思考一下打印结果。

想象着是:

4

defer 2 :  4

3

defer 1 :  3

实际运行结果是:

3
4
defer 2 : 4
defer 1 : 3

理想和现实有些差距,原因是想错了!

===========================================================

另一个问题:defer return 的执行顺序

引自《Go程序设计语言》:

Deferred functions run afther return statements have updated the function's result variables.
Because an anonymous function can access its enclosing function's variables, including named results,
a deferred anoymous function can observer the function's results.
package main

import "fmt"

func main() {
fmt.Println("triple(4) =", triple())
} func double(x int) (result int) {
defer func() { fmt.Printf("double(%d) = %d\n", x, result) }()
return x + x
} func triple(x int) (result int) {
defer func() { result += x }()
return double(x)
}

上面代码中triple函数中的defer在return语句执行完成之后,更新了函数的返回值的变量result,所以结果如下:

double(4) = 8
triple(4) = 12

修改一下代码:

dill@bunbun:~$ vim test.go
package main import "fmt" func main() {
fmt.Println("triple(4) =", triple())
} func double(x int) (result int) {
defer func() { fmt.Printf("double(%d) = %d\n", x, result) }()
return x + x
} func triple(x int) int {
var result int
result = double(x)
defer func() { result += x }()
return result
}

返回结果:

double(4) = 8

triple(4) = 8

我的理解是,执行return语句后,将result赋值给函数的结果变量,这个变量是匿名的。此时result和结果的匿名变量是两个变量,当defer语句更改result值得时候,结果变量不会改变。因此函数的返回结果仍然为defer执行前的result的值。

再修改一下:

package main

import "fmt"

func main() {
fmt.Println("triple(4) =", *(triple()))
} func double(x int) (result int) {
defer func() { fmt.Printf("double(%d) = %d\n", x, result) }()
return x + x
} func triple(x int) *int {
var result int
result = double(x)
defer func() { result += x }()
return &result
}

结果如下:

double(4) = 8
triple(4) = 12

这里利用的指针传递

一个有关Golang Deferred Function 执行顺序的问题的更多相关文章

  1. UIViewController的生命周期及iOS程序执行顺序

    UIViewController的生命周期及iOS程序执行顺序     当一个视图控制器被创建,并在屏幕上显示的时候. 代码的执行顺序1. alloc                         ...

  2. Java静态变量、静态块、构造块、构造函数、main函数、普通代码块的执行顺序

    测试代码 public class SingleTest { public static String v = "StaticValue"; static { System.out ...

  3. Oracle一个事务中的Insert和Update执行顺序

    今天碰到了一个奇怪的问题,是关于Oracle一个事务中的Insert和Update语句的执行顺序的问题. 首先详细说明下整个过程: 有三张表:A,B,C,Java代码中有一段代码是先在表A中插入一条数 ...

  4. 关于Ajax load页面中js部分$(function(){})的执行顺序

    <script type="text/javascript"> console.error(11111); $(function(){ console.error(22 ...

  5. SQL SERVER 一个SQL语句的执行顺序

    一个SQL 语句的执行顺序 1.From (告诉程序 来自哪张表  如果是表表达式 依旧是如此顺序) 2.Where(条件筛选  谓词筛选 ) 3.Group by(分组) 4.Having(分组   ...

  6. 当一个SQL语句同时出现了where,group by,having,order by的时候,执行顺序和编写顺序

    当一个查询语句同时出现了where,group by,having,order by的时候,执行顺序和编写顺序 1.执行where xx对全表数据做筛选,返回第1个结果集. 2.针对第1个结果集使用g ...

  7. autofac 一个接口多个实现的顺序执行

    接口: namespace AutofacTest.Interface { public interface IUserInfo { string GetUserINfo(int uid); int ...

  8. 【Golang基础】defer执行顺序

    defer 执行顺序类似栈的先入后出原则(FILO)     一个defer引发的小坑:打开文件,读取内容,删除文件   // 原始问题代码 func testFun(){ // 打开文件 file, ...

  9. bash执行顺序:alias --> function --> builtin --> program

    linux bash的执行顺序如下所示: 先 alias --> function --> builtin --> program 后 验证过程: 1,在bash shell中有内置 ...

随机推荐

  1. webpack面试题(转载)

    1:webpack打包原理 把所有依赖打包成一个bundle.js文件,通过代码分割成单元片段并按需加载. 2:webpack的优势 (1)       webpack是以commonJS的形式来书写 ...

  2. background的水平条纹和斜向条纹

    水平条纹: <div id="div1"> </div> linear-gradient属性 #div1{ width: 100px; height: 10 ...

  3. 雷电模拟器 v3.71绿色版

    目录 1. 按 2. 介绍 3. 下载地址 1. 按 安卓模拟器目前的市场基本上稳定了,逍遥.夜神.雷电,用的人都很多,网易mumu从阴阳师时代就被大家熟知,腾讯手游助手也是随着吃鸡游戏而火,这两个模 ...

  4. 系统环境: CentOS 64位+千万不要在生产环境中升级glibc!

    # cd /lib64# LD_PRELOAD=/lib64/libc-2.15.so ln -sf /lib64/libc-2.15.so libc.so.6 libc-2.15.so 这个文件名根 ...

  5. Saving James Bond - Easy Version

    题目来源: 浙江大学在慕课网上开设的<数据结构>课,陈越老师.何钦铭老师主讲,课后作业的一道题. 题目描述: 题目思路: 这道题目本质上讲就是列出图的连通集,但是这个连通集的起点是有约束的 ...

  6. jvm slot复用

    如果当前字节码PC计数器的值已经超出了某个变量的作用域,那这个变量对应的Slot就可以交给其他变量使用. 字节码PC计数器就是程序计数器,程序计数器记录当前线程所执行的字节码的偏移地址.如果这个值超出 ...

  7. Manjaro系统和软件安装记录

    Linux桌面环境  ArchLinux官方wiki manjaro官方wiki pacman官方wiki 从www.distrowatch.com可以查看Linux发行版排行榜,可以看到manjar ...

  8. IO流一

    1 Java IO原理 I/O是input/output的缩写,IO技术是非常实用的技术,用于处理设备之间的数据传输.如读写文件,网络通讯等. Java程序中,对于数据的输入输出操作以“流Stream ...

  9. 谷歌将用QUIC传输层技术加速互联网

    安全这个话题,要感谢斯诺登,过去的安全就是攻和防之间的关系,即我们用一种什么样的体系.架构和模式去构建一个密不可破的安全系统.” 对IETF工作组忽视外部观察者看起来是一件甚么微不足道的事情的能力感到 ...

  10. C++ GUI Qt4学习笔记07

    C++ GUI Qt4   qtc++scrollobject编程 事件(event)是由串口系统或者Qt自身产生的,用以响应所发生的各类事情.当用户按下或者松开键盘或者鼠标上的按键时,就可以产生一个 ...