go语言defer go语言default

3.6 Go语言函数的延迟调用(Deferred Code)在以下这段代码中go语言defer,go语言defer我们操作一个文件 , 无论成功与否都需要关闭文件句柄 。这里在三处不同的位置都调用了file.Close()方法,代码显得非常冗余 。
go语言defer我们利用延迟调用来优化代码 。定义后的defer代码,会在return之前返回,让代码显得更加紧凑,且可读性变强,对上面的代码改造如下go语言defer:
我们通过这个示例来看一下延迟调用与正常代码之间的执行顺序
先简单分析一下代码逻辑go语言defer:
【go语言defer go语言default】从输出中,我们可以观察到如下现象:
从这个实例中,我们很明显观察到,defer语句是在return之前执行
如果一个函数内定义了多个defer,则调用顺序为LIFO(后进先出)方式执行 。
仍然是相同的例子,但是在TestDefer中我们定义了三个defer输出 , 根据LIFO原则,输出的顺序是3rd-2nd-1st,根据最后的结果,也是逆向向上执行defer输出 。
就在整理这篇笔记的时候,发现了自己的认知误区,主要是本节实例三中发现的,先来看一下英文的描述:
对于上面的这段话的理解:
下面是代码执行输出,我们来一起分析一下:
虽然在a()函数内,显示的返回了10,但是main函数中得到的结果是defer函数自增后的结果,我们来分析一下代码:
在这篇文章的上一版,我曾经尝试用指针取解释defer修改返回值的类型,但是感觉不够透彻,也让阅读者非常困惑,索性参考了一下go官方blog中的一篇文章,在此基础上进行了扩展 。如需要阅读原文,可以参考下面的文章 。
go语言中关于defer的注意事项举个例子,如下
答案
解析:
defer函数在处理Panic() 和Recover()时的应用
panic函数是内置的go函数,它终止go程序的当前流程并开始panicking,recover函数也是内置的一个go函数,允许你收回处理那些使用了panic函数的goroutine的控制权
来个案例
简单聊聊Golang中defer预计算参数什么是defer
defer 可以保证方法可以在外围函数返回之前调用 。有点像其他言的 try finally
Go语言defer预计算参数
Go 语言中所有的函数调用都是传值的,虽然 defer 是关键字,但是也继承了这个特性 。假设我们想要计算 main 函数运行的时间 , 可能会写出以下的代码:
结果是:
运行结果并不符合我们的预期 , 这个现象背后的原因是什么呢?经过分析,我们会发现调用 defer 关键字会立刻拷贝函数中引用的外部参数,所以 time.Since(startedAt) 的结果不是在 main 函数退出之前计算的 , 而是在 defer 关键字调用时计算的【defer入栈的时候】,最终导致上述代码输出 0s
我们再来看个简单例子来说明上述解释:
当代码运行到defer fmt.Println(test(i))的时候,会把defer右边最外层函数的参数计算完毕,并传递进函数里,但不会执行函数体的代码直到包裹defer的函数返回 。我们先看会把defer右边最外层函数的参数计算完毕,并传递进函数里这句话,对应例子就是先把test(i)算出来,此时i=1 , 计算test(1)得2,然后fmt.Println(2)入栈,等到最后程序运行完了再运行defer结果就是2(但不会执行函数体的代码直到包裹defer的函数返回) 。
我们再来看一个例子与匿名函数结合:
结果:
使用匿名函数,结果是101 , 相当于i给到test方法的是100,那为什么呢?还是那句话:但不会执行函数体的代码直到包裹defer的函数返回
也就是说他会把整个{ fmt.Println(test(i)) }()函数体入栈 , 等到最后程序运行完了再运行defer,此时的i是100,运行test后就是101了 。

推荐阅读