Golang知识点(defer): 面试经常变量在 defer 中的值, 其实在问变量的作用域
变量在 defer 中的值, 其实在问变量的作用域
有没有想过, 面试中经常问的 变量在 defer 之后的值, 其实是在问 函数变量的作用域
简单的说, defer 就是将当前操作放入 堆 中, 等待触发 return
的时候再拿出来执行。 符合堆的特色, 先进后出。
从细节来了, 还需要注意
- 变量 在 defer 中的 作用域 ?
- 函数 的 执行操作 是在 入堆前还是后 ?
- defer 中的函数发生了
panic
会怎样 ?
真题测试
以下这是 go语言爱好者 97 期的一道题目。 要求很简单, 代码执行 i, j 的值分别是什么。
|
|
这道题虽然代码少, 但是考点还是蛮多的
- 核心: 函数变量作用域
- defer 执行时间
- 闭包
- 指针
知识点
这里面所有的内容都可以在 Effective Go 中解决
贪婪算法
什么是贪婪算法, 就是找到局部最优解, 合并后就是全局最优解。
怎么找局部最优解, 就是要 对事情进行抽象,掌握事情的本质 。
defer 延迟执行
defer 就是语句进行压栈(FILO
)处理, 延迟到 在函数 return
之前执行 执行。
本身没什么难点。 其设计目的也很明确就是为了 解决资源释放 的问题。
open
和close
写在一起, 语意更直观。- 解决因为错误退出,导致而 无法或忘记 释放资源
Effective Go 中对
defer
的概述。It’s an unusual but effective way to deal with situations such as resources that must be released regardless of which path a function takes to return.
这是一种不寻常但有效的方法来处理诸如必须释放资源的情况,而不管函数采用哪条路径返回。
因此 defer 有什么好考的, 而且实际场景代码也不会那样写(违反了可读性的这一基本之准则)。
所以通常面试中有 defer 的问题都不是在考 defer , 只不过是披上了 defer 的狼皮。
函数及返回值
其实 go 中关于函数返回花样还是挺多的。
- 命名的/匿名的 返回值
func NamedResult(i, j int) (x int)
- 带参数不带参数的 return
return
感觉和 golang 本身的代码可读性的的理念有一点冲突。 就像为什么不支持三元运算符一样。 其实这样本身也没有什么, 就是一两个 死记硬背 的知识点而已。
但是遇到了 defer
, 闭包
, 指针
中对变量有操作, 那么问题可能就大了。
如果对 函数变量的作用域 理解不清楚的话, 就容易掉坑。
|
|
我们开启汇编, 查看一下函数过程
|
|
从汇编结果可以看到:
- 虽然我们在
UnnamedResult
代码中没有显式的提供返回值的变量名, 但是 golang 自动为我们生成了一个叫~r2
变量名, 其 等价于NamedResult
函数中的变量x
- 汇编中
RET
后没有带任何参数
- 所有与结果有关的操作都标记了
(SP)
, ex:MOVQ AX, "".~r2+24(SP)
既然如此, 我们就将所有函数的写法全部统一, 不再区分 命名的、 匿名的 , 默认的, 指定的
- 命名返回值
- return 指定结果
|
|
这样看起来, 整个函数就清晰的多了。
实战练习一下
根据之前所说, 我们这里来对函数做一下整形手术。
|
|
这样看, defer 是不是很简单了啊?
- 原文链接:https://typonotes.com/posts/2021/06/21/golang-defer-func-variables-scope/
- 本文为原创文章,转载注明出处。
- 欢迎 扫码关注公众号
Go与云原生
或 订阅网站 https://typonotes.com/ 。 - 第一时间看后续精彩文章。觉得好的话,请猛击文章右下角「在看」,感谢支持。