使用defer解决实际问题
引入
首先我们以leetcode上面的一道题目引入

思路
这道题非常的简单,我们简单的提取一下关键字:头节点,从尾到头。其实读到这里我们就有了做这道题的思路,链表的头节点说明我们的数据源在链表中,从尾到头其实就是栈规则,它遵循一个先进后出的原则,而这道题我们就可以使用这个思想来解题。我们首先按照正常思路来实现
方法一
1 | type stack []int |
这种解题方式就是我们手动实现了一个栈规则,并将数据以栈的规则入栈并返回。讲到这里可能大家会觉得偏移了本章的主题,别着急,接下来就进入本章的主题了
defer简介
相信大家多多少少都使用过defer这个关键字,用的比较多的场景:异常的捕获、更加安全的资源回收等,其实我们在开发中使用它时关注的点都是其功能的本身,并没有过多的在意其的运行机制,所以本章就先简单的讲解一下其中的机制
多个defer的运行顺序
在程序中如果我们使用多个defer他的运行顺序会是什么呢?我们来看一下下面这段代码:
1 | package main |

我们不需要很仔细的看这段代码就可以发现,其实defer的运行机制其实就是符合栈规则的,先进后出
参数的计算
我们再来砍断代码:
1 | func main() { |
这次我们并没有直接使用常量来进行输出,而是通过循环变量来输出,下面是运行截图

其实在GO中所有的函数调用都是传值的,defer所软是一个关键字,但是他也继承了这个特性,如果我们想要计算main函数的运行时间,我们可能会写出下面的一段代码
1 | func main() { |
其实这段代码的运行结果是不符合我们的预期的,进过简单的分析其实我们可以发现在调用defer关键字时defer会立刻将参数拷贝,然后再进行延迟运行,最后会输出0秒:

虽然这里输出的是265ns,但是他并没有输出我们sleep的时间,所以并没有实现我们计算mian函数运行时间的需求。
其实解决这个问题也非常的简单,我们只需要将计算时间这段业务代码放在匿名函数中就有可以解决:
1 | package main |

这是什么原理呢?虽然defer关键字使用值传递,但是应为拷贝的是函数指针,所以time.Since(startedAt)会在mian函数返回后调用并且返回我们想要的结果
回到题目
我们对defer的特性进行了一个简单的介绍,其实我们能发现,他拥有着栈的特性,所以我们可以结合他的特性来解这道题目:
1 | /** |

- Post title: 使用defer解决实际问题
- Create time: 2020-12-03 16:11:46
- Post link: post/17075.html
- Copyright notice: All articles in this blog are licensed under BY-NC-SA unless stating additionally.