Go技巧 - Variable Shadowing
Go
语法中有一个较为隐蔽的特性 - Variable Shadowing
,常被翻译为 变量隐藏。官方对这块提供的资料很少,经常有不少Go
语言开发者在这块“踩雷”。
语法意义 - 作用域
既然Go
官方支持这个特性,那就有对应的语法意义,简而言之就是 控制变量的作用域。
下面是一个简单的示例:
1 | func main() { |
而其中的x := 1
是创建了一个新的变量,它的作用域仅在 if true
之后的括号内。当离开作用域之后, x
变量又回到了原值。
一个隐蔽的错误示例
上述示例可以将 x := 1
修改为 x = 1
,或者重新命名变量x
,就可以避免引入 variable shadowing
。
但在实际开发中,常常出现一些隐蔽的case:
1 | func main() { |
在多变量返回时,很容易出现variable shadowing
的情况。例如,上述示例中的b, err := bar()
,有两个返回值:
b
,前文未定义,作用域仅在对应的括号中,不会出现问题err
,前文已定义,这里发生了variable shadowing
,所以在括号内外是两个变量
由于Go
语言推荐将error
作为最后一个返回值,所以往往在error这个变量上会发生variable shadowing
,常被称为error shadowing
。
尽管官方支持这种语法,但很容易发生预期不一致的结果。社区也提供了相关的工具shadow
,可用下方的命令快速体验:
1 | go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest |
用工具可以发现问题,但如何解决呢?我推荐两个思路:
思路一:移除:=
赋值使用
variable shadowing
常出现的场景是多变量返回,并且同时存在已定义与未定义的变量。那么,我们可以尝试提前定义所需的变量,移除:=
的赋值方式。例如将示例改造为:
1 | var b string |
这种提前定义的方式会增加代码量,但它不仅避免了variable shadowing
,还有一个比较大的优势:提高可读性。
一行简单的变量定义,尤其是当定义的内容是一个复杂对象时,我们能从这个定义中读到很多内容,如一个var fe foo.Example
,让变量简写fe
和变量的定义foo.Example
结合在一起,非常清晰。
思路二:重命名
重命名时,我们对变量有两种处理方式,以下面的errB
为例:
1 | var err error |
个人推荐方案
1 | // 变量的生命周期 - 仅在括号内 |
以上是我个人的一种编程习惯,能减少因 variable shadowing
发生错误的概率,希望能帮助到各位同学。
编程思考 - 表述不清晰,往往是因为掌握得不够深入
在写方案、查问题、沟通业务时,开发者们经常有种感觉 - 我已经表达得很清晰了,但别人常常无法听懂。
我也经常遇到这种情况。以前,我会觉得是对方的问题,如对相关领域的知识储备太少;而现在,我更倾向于是自己对这块内容的掌握度仍不够,导致无法通俗易懂地表达。
我的思维主要有两点转变:
- 大师能面向不同人群、通俗易懂地讲清深奥的知识;
- 改变优先从自身出发,而不是寄希望于他人的主动变化;
当收到他人对你表述不清晰的评价时,不要过于抵触,不妨趁这个机会再深入研究相关知识点,提升自己的水平。
工作生活 - 你看到的,是你想看到的
最近读完了《拆掉了思维里的墙》,我印象最深的一句话是:你看到的,是你想看到的。
这个世界可能是客观的,但每个人的世界都是主观的。在事前或者事后,很多人都清楚该以什么样的态度面对世界,理论上很完美;但事到临头,面对带有负面内容的事物,我们往往会不自觉地以自己最习惯的方式来抵抗、躲避。
如果你想看到一个自己理想中的世界,往往需要一定的锻炼,形成“肌肉记忆”,让自己的心态变得更强壮。
Github: https://github.com/Junedayday/code_reading
Blog: http://junes.tech/
Bilibili: https://space.bilibili.com/293775192
公众号: golangcoding