defer 延迟调用
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 延迟调用的更多相关文章
- Swift Defer 延迟调用
1.Defer 在一些语言中,有 try/finally 这样的控制语句,比如 Java.这种语句可以让我们在 finally 代码块中执行必须要执行的代码,不管之前怎样的兴风作浪.在 Swift 2 ...
- go语言基础之defer延迟调用
1.defer作用 关键字 defer ⽤于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行.注意,defer语句只能出现在函数或方法的内部. 运行场景: defer语句经常被用于处理成对的操作 ...
- ReactiveSwift源码解析(十一) Atomic的代码实现以及其中的Defer延迟、Posix互斥锁、递归锁
本篇博客我们来聊一下ReactiveSwift中的原子性操作,在此内容上我们简单的聊一下Posix互斥锁以及递归锁的概念以及使用场景.然后再聊一下Atomic的代码实现.Atomic主要负责多线程下的 ...
- Twisted 延迟调用
延迟(defer)是twisted框架中实现异步的编程体系,使程序设计可以采用事件驱动的机制 1.基本使用 defer可以看作一个管理回调函数的对象,可以向该对象添加需要的回调函数同时也可以指定该组函 ...
- 17_defer(延迟调用)关键字的使用
1.defer是延迟调用关键字,只能在函数内部使用 2.总是在main函数结束前调用(和init用法相对) 3.如果有多个defer 遵循先进后出的原则 4.和匿名函数同时使用时,如果匿名函数带有参数 ...
- go 学习笔记之解读什么是defer延迟函数
Go 语言中有个 defer 关键字,常用于实现延迟函数来保证关键代码的最终执行,常言道: "未雨绸缪方可有备无患". 延迟函数就是这么一种机制,无论程序是正常返回还是异常报错,只 ...
- Go语言系列开发之延迟调用和作用域
Hello,各位小伙伴大家好,我是小栈君,最近一段时间我们将继续分享关于go语言基础系列,当然后期小栈君已经在筹划关于java.Python,数据分析.人工智能和大数据等相关系列文章.希望能和大家一起 ...
- go 学习笔记之咬文嚼字带你弄清楚 defer 延迟函数
温故知新不忘延迟基础 A "defer" statement invokes a function whose execution is deferred to the momen ...
- 【Unity3D】Invoke,InvokeRepeating ,Coroutine 延迟调用,周期性调用
Invoke和InvokeRepeating方法,可以实现延迟调用,和周期调用 第一个是执行一次,第二个是重复执行 void Invoke(string methodName, float time) ...
随机推荐
- linux 部署jar包开机自启
1.用xShell将jar包上传到linux上(jar包上传到 /root/java) 输入rz命令,看是否已经安装了lrzsz,如果没有安装则执行 yum -y install lrzsz ...
- Communication-Efficient Learning of Deep Networks from Decentralized Data
郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! Proceedings of the 20th International Conference on Artificial Intell ...
- SQL语句组合查询 UNION
1.使用UNION UNION 可以涉及编写多条SELECT语句,首先看看单条语句 第一条SELECT语句把Illinois,Indiana,Michigan等州的缩写传递给IN子句,检索出这些州的所 ...
- 写Seo网站标题应该注意什么
http://www.wocaoseo.com/thread-11-1-1.html 最近看了群里一些朋友讨论关于网站优化标题应该注意哪些?各种说法五花八门,好的seo优化标题是可以给网站带来不错的流 ...
- wampserver64 apache2.4版本局域网互相访问总结
wampserver64 apache2.4版本局域网互相访问总结 背景:在我的电脑上给算法组开发了一个工具,需要在局域网环境下其他同事都能访问到,搞了一下午终于搞定,于是整理了这篇文档,给其他同行 ...
- Android开发之Toast吐司的一个封装好的工具类。带有源代码java文件,
import android.content.Context; import android.widget.Toast; //Toast统一管理类 public class T { private T ...
- android开发之java代码中如何获取到当前时间。详情代码带注释。
/** *获取当前时间 * @return */ public String getTime(){ Date date= new Date();//创建一个时间对象,获取到当前的时间 SimpleDa ...
- lua 优化
彻底解析Android缓存机制——LruCache https://www.jianshu.com/p/b49a111147ee lua:部分常用操作的效率对比及代码优化建议(附测试代码) https ...
- 【代码优化】Unity查漏补缺
1.XML: 使用Unity社区中的开源脚本(Js语言)解析XML文件,网址:http://dev.grumpyferret.com/unity/,已打包XMLParser.unitypackage, ...
- 尝试MatCap类型shader
听说MatCap能在低端机上做出很漂亮的pbr效果,就尝试了一下. MatCap全称MaterailCapture,里面存的是光照信息,通过法线的xy分量去采样matcap,得到在该方向法线的光照信息 ...