1. 延迟调用

defer 的用法很简单,只要在后面跟一个函数的调用,就能实现将这个  xxx 函数的调用延迟到当前函数执行完后再执行。

defer xxx() 
 

这是一个很简单的例子,可以很快帮助你理解 defer 的使用效果。

import "fmt"

func myfunc() {
fmt.Println("B")
} func main() {
defer myfunc()
fmt.Println("A")
}
 

输出如下

A
B
 

当然了,对于上面这个例子可以简写为成如下,输出结果是一致的

import "fmt"

func main() {
defer fmt.Println("B")
fmt.Println("A")
}
 

2. 即时求值的变量快照

使用 defer 只是延时调用函数,此时传递给函数里的变量,不应该受到后续程序的影响。

比如这边的例子

import "fmt"

func main() {
name := "go"
defer fmt.Println(name) // 输出: go name = "python"
fmt.Println(name) // 输出: python
}
 

输出如下,可见给 name 重新赋值为 python,后续调用 defer 的时候,仍然使用未重新赋值的变量值,就好像在 defer 这里,给所有的变量做了一个快照一样。

python
go
 

3. 多个defer 反序调用

当我们在一个函数里使用了 多个defer,那么这些defer 的执行函数是如何的呢?

做个试验就知道了

import "fmt"

func main() {
name := "go"
defer fmt.Println(name) // 输出: go name = "python"
defer fmt.Println(name) // 输出: python name = "java"
fmt.Println(name)
}
 

输出如下,可见 多个defer 是反序调用的,有点类似栈一样,后进先出。

java
python
go
 

3. defer 与 return 孰先孰后

至此,defer 还算是挺好理解的。在一般的使用上,是没有问题了。

在这里提一个稍微复杂一点的问题,defer 和 return 到底是哪个先调用?

使用下面这段代码,可以很容易的观察出来

import "fmt"

var name string = "go"

func myfunc() string {
defer func() {
name = "python"
}() fmt.Printf("myfunc 函数里的name:%s\n", name)
return name
} func main() {
myname := myfunc()
fmt.Printf("main 函数里的name: %s\n", name)
fmt.Println("main 函数里的myname: ", myname)
}
 

输出如下

myfunc 函数里的name:go
main 函数里的name: python
main 函数里的myname: go
 

来一起理解一下这段代码,第一行很直观,name 此时还是全局变量,值还是go

第二行也不难理解,在 defer 里改变了这个全局变量,此时name的值已经变成了 python

重点在第三行,为什么输出的是 go ?

解释只有一个,那就是 defer 是return 后才调用的。所以在执行 defer 前,myname 已经被赋值成 go 了。

4. 为什么要有 defer?

看完上面的例子后,不知道你是否和我一样,对这个defer的使用效果感到熟悉?貌似在 Python 也见过类似的用法。

虽然 Python 中没有 defer ,但是它有 with 上下文管理器。我们知道在 Python 中可以使用 defer 实现对资源的管理。最常用的例子就是文件的打开关闭。

你可能会有疑问,这也没什么意义呀,我把这个放在 defer 执行的函数放在 return 那里执行不就好了。

固然可以,但是当一个函数里有多个 return 时,你得多调用好多次这个函数,代码就臃肿起来了。

若是没有 defer,你可能这样写代码

func f() {
r := getResource() //0,获取资源
......
if ... {
r.release() //1,释放资源
return
}
......
if ... {
r.release() //2,释放资源
return
}
......
if ... {
r.release() //3,释放资源
return
}
......
r.release() //4,释放资源
return
}
 

使用了 defer 后,代码就显得简单直接了,不管你在何处 return,都会执行 defer 后的函数。

func f() {
r := getResource() //0,获取资源 defer r.release() //1,释放资源
......
if ... {
...
return
}
......
if ... {
...
return
}
......
if ... {
...
return
}
......
return
}
 

defer 延迟调用的更多相关文章

  1. Swift Defer 延迟调用

    1.Defer 在一些语言中,有 try/finally 这样的控制语句,比如 Java.这种语句可以让我们在 finally 代码块中执行必须要执行的代码,不管之前怎样的兴风作浪.在 Swift 2 ...

  2. go语言基础之defer延迟调用

    1.defer作用 关键字 defer ⽤于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行.注意,defer语句只能出现在函数或方法的内部. 运行场景: defer语句经常被用于处理成对的操作 ...

  3. ReactiveSwift源码解析(十一) Atomic的代码实现以及其中的Defer延迟、Posix互斥锁、递归锁

    本篇博客我们来聊一下ReactiveSwift中的原子性操作,在此内容上我们简单的聊一下Posix互斥锁以及递归锁的概念以及使用场景.然后再聊一下Atomic的代码实现.Atomic主要负责多线程下的 ...

  4. Twisted 延迟调用

    延迟(defer)是twisted框架中实现异步的编程体系,使程序设计可以采用事件驱动的机制 1.基本使用 defer可以看作一个管理回调函数的对象,可以向该对象添加需要的回调函数同时也可以指定该组函 ...

  5. 17_defer(延迟调用)关键字的使用

    1.defer是延迟调用关键字,只能在函数内部使用 2.总是在main函数结束前调用(和init用法相对) 3.如果有多个defer 遵循先进后出的原则 4.和匿名函数同时使用时,如果匿名函数带有参数 ...

  6. go 学习笔记之解读什么是defer延迟函数

    Go 语言中有个 defer 关键字,常用于实现延迟函数来保证关键代码的最终执行,常言道: "未雨绸缪方可有备无患". 延迟函数就是这么一种机制,无论程序是正常返回还是异常报错,只 ...

  7. Go语言系列开发之延迟调用和作用域

    Hello,各位小伙伴大家好,我是小栈君,最近一段时间我们将继续分享关于go语言基础系列,当然后期小栈君已经在筹划关于java.Python,数据分析.人工智能和大数据等相关系列文章.希望能和大家一起 ...

  8. go 学习笔记之咬文嚼字带你弄清楚 defer 延迟函数

    温故知新不忘延迟基础 A "defer" statement invokes a function whose execution is deferred to the momen ...

  9. 【Unity3D】Invoke,InvokeRepeating ,Coroutine 延迟调用,周期性调用

    Invoke和InvokeRepeating方法,可以实现延迟调用,和周期调用 第一个是执行一次,第二个是重复执行 void Invoke(string methodName, float time) ...

随机推荐

  1. python 计算文件md5值

    md5是一种常见不可逆加密算法,使用简单,计算速度快,在很多场景下都会用到,比如:给用户上传的文件命名,数据库中保存的用户密码,下载文件后检验文件是否正确等.下面讲解在python中如何使用md5算法 ...

  2. ping通网关 ping不通dns

    一.Request Timed Out 当Ping指定的对象时,出现“Request Timed Out”提示信息的频率非常高,这说明对方无法接受发送过来的数据.当然这种情况下,很可能就是网络出现了故 ...

  3. Spring Security认证流程分析--练气后期

    写在前面 在前一篇文章中,我们介绍了如何配置spring security的自定义认证页面,以及前后端分离场景下如何获取spring security的CSRF Token.在这一篇文章中我们将来分析 ...

  4. 利用python爬取贝壳网租房信息

    最近准备换房子,在网站上寻找各种房源信息,看得眼花缭乱,于是想着能否将基本信息汇总起来便于查找,便用python将基本信息爬下来放到excel,这样一来就容易搜索了. 1. 利用lxml中的xpath ...

  5. 深度学习调参笔记(trick)

    1. Adam 学习率0.00035真香: 2. SGD + Momentum 学习率应当找到合适区间,一般远大于Adam (取1,2,5,10这类数据): 3. 提前终止,防止过拟合; 4. Ens ...

  6. 微信支付宝个人免签约即时到帐接口开发附demo

    支付界面: 扫码支付界面: 付成功后可以跳转到你程序指定的地址! demo: http://likeyunba.com/WeChat-Pay/

  7. 51,N皇后

    from typing import List# 这道题还是比较经典的深搜递归调用的问题.# 只需要保证二维列表的每一行,每一列,每一对角线只有一个皇后就好了.class Solution: def ...

  8. iOS 64位静态链接库

    https://www.jianshu.com/p/486e3b737707 https://stackoverflow.com/questions/44635297/setting-an-ios-s ...

  9. django学习(三)

    1.单表操作和测试环境的准备 我们先对单表查询做一个总结和回顾,并进行进一步的学习和交流.我们在我们的应用的models.py文件下面书写user类.如下所示,然后用数据库迁移,在mysql数据库中生 ...

  10. 知识点干货——CSS动画

    CSS动画 (transition.animation) //2D动画 transform:translate(); /*偏移*/ transform:rotate(); /*旋转角度*/ trans ...