golang中defer的详解 转自https://blog.csdn.net/skh2015java/article/details/77081250
Go里的defer很有用,尤其在很多执行模块化操作时,初始化时给各个需要执行的模块传入参数,但是这些参数有些事在模块执行过程中才赋值的。
这时候有了defer就不会把代码写的很凌乱。
Go的defer语句用来调度一个函数调用(被延期的函数),使其在执行defer的函数即将返回之前才被运行,被延期执行的函数,它的参数(包括接受者)实在defer执行的时候被求值的,而不是在调用执行的时候。也就是说被延期执行的函数的参数是按正常顺序被求值的。
defer会按逆序执行
defer是Go语言提供的关键字,常用来释放资源,会在函数返回之前进行调用。如果有多个defer表达式,调用顺序类似于栈,越后面的defer表达式越先被调用。defer 函数调用的执行时机是外层函数设置返回值之后, 并且在即将返回之前。
例1:
func main() {
for i:=0 ;i<5;i++{
defer fmt.Printf("%d",i)
fmt.Println("bbbbb")
}
fmt.Println("aaaaa")
}
执行结果:
bbbbb
bbbbb
bbbbb
bbbbb
bbbbb
aaaaa
43210
例2:
func trace(s string) string {
fmt.Println("entering:",s)
return s
}
func un(s string) {
fmt.Println("leaving:",s)
}
func a() {
defer un(trace("a"))
fmt.Println("in a")
}
func b() {
defer un(trace("b"))
fmt.Println("in b")
a()
}
func main() {
b()
}
执行结果如下:
entering: b
in b
entering: a
in a
leaving: a
leaving: b
例3
func f1() (result int) {
defer func() {
result++
}()
return 0
}
func f2() (r int) {
t := 5
defer func() {
t = t+5
}()
return t
}
func f3() (t int) {
t = 5
defer func() {
t = t+5
}()
return t
}
func f4() (r int) {
defer func(r int) {
r = r + 5
}(r)
return 1
}
要使用defer不踩坑,最重要的一点就是明白,return xxx不是一条原子指令
函数返回的过程是这样子的:先给返回值赋值,然后调用defer表达式,最后才是返回到调用函数中。
defer表达式可能会在设置函数返回值之后,在返回到调用函数之前,修改返回值,使最终的函数返回值与你想象的不一致。
可以将return xxx改成
返回值=xxx
调用defer函数
空的return
例3可以改写成这样
func f11() (result int) {
result = 0 //先给返回值赋值
func(){ //再执行defer 函数
result++
}()
return //最后返回
}
func f22() (r int) {
t := 5
r = t //赋值指令
func(){ //defer 函数被插入到赋值与返回之间执行,这个例子中返回值r没有被修改
t = t+5
}
return //返回
}
func f33() (t int) {
t = 5 //赋值指令
func(){
t = t+5 //然后执行defer函数,t值被修改
}
return
}
func f44() (r int) {
r = 1 //给返回值赋值
func(r int){ //这里的r传值进去的,是原来r的copy,不会改变要返回的那个r值
r = r+5
}(r)
return
}
参考:《Effective Go》、《深入解析go内核实现》
golang中defer的详解 转自https://blog.csdn.net/skh2015java/article/details/77081250的更多相关文章
- golang语言并发与并行——goroutine和channel的详细理解(一) 转发自https://blog.csdn.net/skh2015java/article/details/60330785
如果不是我对真正并行的线程的追求,就不会认识到Go有多么的迷人. Go语言从语言层面上就支持了并发,这与其他语言大不一样,不像以前我们要用Thread库 来新建线程,还要用线程安全的队列库来共享数据. ...
- Window 对象详解 转自 http://blog.csdn.net/jcx5083761/article/details/41243697
详解HTML中的window对象和document对象 标签: HTMLwindowdocument 2014-11-18 11:03 5884人阅读 评论(0) 收藏 举报 分类: HTML& ...
- 28 Corn表达式详解 (转自http://blog.csdn.net/claram/article/details/51785193)
Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式: Seconds Minutes Hours DayofMonth Month ...
- .net反射详解 原文://http://blog.csdn.net/wenyan07/article/details/27882363
概述反射 通过反射可以提供类型信息,从而使得我们开发人员在运行时能够利用这些信息构造和使用对象. 反射机制允许程序在执行过程中动态地添加各种功能. 运行时类型标识 运行时类型标识(RTTI),可以在程 ...
- springboot项目--传入参数校验-----SpringBoot开发详解(五)--Controller接收参数以及参数校验----https://blog.csdn.net/qq_31001665/article/details/71075743
https://blog.csdn.net/qq_31001665/article/details/71075743 springboot项目--传入参数校验-----SpringBoot开发详解(五 ...
- 虚拟机中的CentOS7如何上网?---https://blog.csdn.net/nothing2017/article/details/61420767
虚拟机中的CentOS7如何上网?https://blog.csdn.net/nothing2017/article/details/61420767
- Golang拼接字符串的5种方法及其效率_Chrispink-CSDN博客_golang 字符串拼接效率 https://blog.csdn.net/m0_37422289/article/details/103362740
Different ways to concatenate two strings in Golang - GeeksforGeeks https://www.geeksforgeeks.org/di ...
- 向txt文件中写入内容(覆盖重写与在末尾续写+FileOutputStream与FileWriter)(转发:https://blog.csdn.net/bestcxx/article/details/51381460)
!!!! 读取txt文件中的内容 import java.io.BufferedReader; import java.io.File; import java.io.FileReader; /** ...
- Redis中为什么使用跳表---------转自http://blog.csdn.net/u010412301/article/details/64923131
最近在研究数据库的一些底层实现,百度的面试官问到了跳表,当时没有回答上来,在csdn上看到了这篇文章,感觉写的比较好,希望大家可以多多交流. Redis里面使用skiplist是为了实现sorted ...
随机推荐
- angular 项目 error TS2451: Cannot redeclare block-scoped variable 'ngDevMode'
删除 node_modules ,用 npm install 就可以了, cnpm install (竟然不行)
- HDU 1205 吃糖果(想想题)
题目传送:http://acm.hdu.edu.cn/showproblem.php?pid=1205 Problem Description HOHO,终于从Speakless手上赢走了所有的糖果, ...
- GCC内置函数
在C语言写的程序中,有时候没有包含头文件,直接调用一些函数,如printf,也不会报错,因为GCC内置和一些函数.如果包含了头文件,则去第三方库中链接这个函数,不再使用GCC内置的函数.每个编译器的内 ...
- redis的哨兵模式
我是在一台服务器上安装了三个redis 一主两从 想安装gcc gcc-c++ make tcl lrzsz yum -y install gcc gcc-c++ make tcl lrzsz ...
- Ubuntu 12.04不能在華碩F81se系列電腦上安裝解决辦法
本人華碩F81se系列的電腦,剛開始是裝的ubuntu 10.04的系統,周末閑的無聊,就想把系統換成ubuntu 12.04的,從ubuntu官網上下載了12.04的安裝包,下了個usb insta ...
- java错误:找不到或无法加载主类
问题: 在 windows cmd 中编译后,运行 java 文件时,出现此错误 分析: 源文件 ClientDemo.java: package netdemo; public class Clie ...
- Vim+Ctags+Cscope安装
对比了下,感觉还是Vim比较专业. 一:使用说明: ‘/’查找忽略大小写,比如需要查找“book”,当输入/b的时候会自动找到第一个以"b"开头的单词 实现C程序的缩减 查询中自由 ...
- ng-repeat的用法:
-------------------------------------转载: 遍历数组: <li ng-repeat="item in array">{{it ...
- nginx实现集群高可用
大家知道NGINX作为反向代理服务器可以实现负载均衡,同时也可以作为静态文件服务器,它的特点就是并发支持大,单机可同时支持3万并发,现在很多网站都把NGINX作为网关入口来统一调度分配后端资源.但是如 ...
- ElasticSearch安装部署,基本配置(Ubuntu14.04)
ElasticSearch部署文档(Ubuntu 14.04) 安装java sudo add-apt-repository ppa:webupd8team/java sudo apt-get upd ...