大家好,我是炸鱼。最近在翻看Go的一些历史提案的时候,发现有一些很神奇的提案,提出了很多年了,但是至今还没有关闭,人们在不断的讨论,但是始终无法解决。有一种“气死我也打不死”的感觉。今天建宇就带大家来看看它到底是个什么东西。背景今天这篇文章介绍的Go方案《proposal: spec: various changes to :=》是经典中的经典,是初学者在学习时的通病。这个提案是从2009年开始提出的,最近一次热议是在2021年:代码原型如下:funcf()(erros.Error){v,err:=g()iferr!=nil{return}ifv{v,err:=h()iferr!=nil{return}}}这段代码的问题是if语句中的:=导致创建一个新的err变量,从而导致返回参数被覆盖。即Go中的:=重赋值逻辑会导致参数被覆盖,造成隐患。新提案开头提到,这是一个已经过去了13年,到2022年仍然没有定论的提案。总结整个提案和其他内部思路,大家提出了以下解决方案或思路:添加语法糖。摆脱语法。设定规范。语法糖这个想法删除了重新声明:=语法并为新变量声明添加了新的:和::语法。代码如下:packagebarfuncfoo(){varx,err=f()...//这里的“:err”表示上面声明的err。vary,z,:err=g()...{//实际上,:err表示代码块中声明的错误。varw,:err=h()...//::err表示在包级别声明的错误。varu,v,::err=j()...//这个“err”是一个新语句。varm,n,err=k()...}}上面代码中给出了三种情况,即:var:err=x:表示最新作用域声明的err,本义指的是上面声明的err,所以你会发现在代码块里和外面,它代表的是不同的结果。var::err=x:表示在包级别声明的错误。varerr=x:表示新的声明。在另一个提案《proposal: Go 2: let := support any l-value that = supports》中,Go语言之父@RobPike直接表示要去掉:=重新赋值的方法,而不是去修补它。添加一堆会使它变得更复杂。如下图:我认为我们的目标应该是消除重复声明,如果我们可以构建一个更平滑的错误处理模型,那么重复声明就会变得不那么明显。不过,这不会很快发生。删除功能而不是添加功能。(喊:lessismore)单行多声明首先修改重新赋值的语义,所有在:=左边的标识符总是声明为新变量,并且不允许在同一块内重新声明。如下代码:a,err:=foo()b,err:=foo()//编译错误,因为在这个块中已经声明了varerr,所以第一行声明正常,第二行由于re-declaration在同一个代码块中声明,所以会出现编译错误,因为已经声明过了。然后添加了语法功能以允许在一行中混合使用=和:=。如下代码://a和err被声明并初始化(相当于:a,err:=foo()a:=,err:=foo()//b被声明并初始化,而err只是被赋值了一个新的valueb:=,err=foo()iftrue{//c在if块中被声明和初始化,err被赋予一个新值c:=,err=foo()}iftrue{//d和err都是在if块中声明的if,err是隐藏的d:=,err:=foo()}允许一行声明多次,本质上是明确了声明的范围,增加了代码可读性的复杂度。总结今天的文章给大家介绍一个13年前(2009年)发现的神坑,我刚学Go的时候也遇到过很多教程和文档,同学们都会遇到这个reassignment语句的神坑,其实就是上面3个这个解决方案似乎从不同的角度完成了这个重声明的语法糖,但同时也增加了复杂度。说不定直接干掉它也可能是个不错的选择?文章持续更新中。可以微信搜索【脑补炸鱼】阅读。本文已收录在GitHubgithub.com/eddycjy/blog中。学习Go语言可以看Go学习地图和路线。欢迎星星提醒。推荐阅读Go语言入门系列:Go项目实战初探Go语言编程之旅:深入使用Go作为项目Go语言设计哲学:Go语言的理解why与设计思考Go语言进阶之旅:进一步深入Go源码
