最近社区的同学和 Go 官方又因为错误处理的提案屡屡被否,发生了一些小的摩擦。也非常难得的看到核心团队成员首次表达了目前的态度和情况。
基于此,我们今天进行该内容分享。紧跟 Go 官方最新进展。
快速背景
Go 的错误处理机制,主要是依赖于 if err != nil
的方式。因此在对函数做一定的封装后。
代码会呈现出以下样子:
jy1, err := Foo1() if err != nil { return err } jy2, err := Foo2() if err != nil { return err } err := Foo3() if err != nil { return err } ...
有部分开发者会认为这比较的丑陋、混乱且难以阅读。因此 Go 错误处理的优化,也是社区里一直反复提及和提出的领域。饱受各类争议。
新提案:追求类似 try-catch
最近一位国内的同学 @xiaokentrl 提了个类似 try catch error 的新提案,试图用魔法打败魔法。
原作者给出的提案内容是:
1、新增环境变量做开关:
ERROR_SINGLE = TRUE //error_single = true
2、使用特定标识符来做 try-catch:
Demo1 单行错误处理:
//Single-line error handling file, err := os.Create("abc.txt") @ return nil , err defer file.Close()
Demo2 多行错误处理:
func main() { //Multiline error handling :@ file, err:= os.Open("abc.txt") defer file.Close() buf := make([]byte, 1024) _, err2 := file.Read(buf) @ err | err2 return ... }
主要的变化内容是:利用标签 @ 添加一个类似 try-catch 的代码区块,并添加运算符和相关错误处理的联动规则。
这个提案本身,其实就是以往讲到的 goto error 和 check/with 这种类似 try-catch 的模式。
当然非常快的就遭到了 Go 核心团队的反对:
@Ian Lance Taylor 表示:由于很难处理声明和应用,如果一个标签的作用域中还有其他变量,就不能使用 goto。
新的争端:官方你行你上
社区中有同学看到这一次次被否的错误处理和关联提案们,深感无奈和无语。他发出了以下的质疑:
“为什么不让 Ian Lance Taylor 和/或 Go 核心团队的其他成员提出改进的错误处理框架的初始原型,然后让 Go 社区参与进来,为其最终形式做出贡献呢?Go 中的泛型正是这样发展到现在的。
如果我们等待 Go 社区提出最初的原型,我认为我们将永远不会有改进的 Go 错误处理框架,至少在未来几年内不会。”
但其实很可惜,因为人家真干过。
Go 核心团队是有主动提出过错误处理的优化提案的,提案名为《Proposal: A built-in Go error check function, try》,快速讲一下。
以前的代码:
f, err := os.Open(filename) if err != nil { return …, err // zero values for other results, if any }
应用该提案后的新代码:
f := try(os.Open(filename))
try 只能在本身返回错误结果的函数中使用,且该结果必须是外层函数的最后一个结果参数。
不过很遗憾,该官方提案,喜提有史以来被否决最多的提案 TOP1:
最终该提案也由于形形色色的意见,最终凉了。感觉也给 Go 核心团队泼了一盆凉水,因为这是继 check/handle 后的 try,到目前也没有新的官方提案了。
Go 官方回应
本次提及的新提案下,大家的交流愈演愈烈,有种认为就是 Go 核心团队故意不让错误处理得到更好的改善。
此时 Go 核心团队的元老之一 @Ian Lance Taylor 站出来发声,诠释了目前 Go 团队对此的态度。这也是首次。
具体内容如下:
“我们愿意考虑一个有良好社区支持的好的错误处理提案。
不幸的是,我很遗憾地说,基本上所有新的错误处理提案都不好,也没有社区支持。例如,这个提案有 10 个反对票,没有赞成票。我当然会鼓励人们在广泛使用这门语言之前,避免提交错误处理提案。
我还鼓励人们审查早期的提案。它们在这里:github.com/golang/go/i… 。目前已有 183 个并在不断增加。
我自己阅读了每一个。重要的是,请记住,对已被否决提案的微调的新提案也几乎肯定也会被否决。
并且请记住,我们只会接受一个与现有语言契合良好的提案。例如:这个提案中使用了一个神奇的 @ 符号,这完全不像现有语言中的任何其他东西。
Go 团队可能会在适当的时候提出一个新的错误处理提案。然而,正如其他人所说,我们最好的想法被社区认为是不可接受的。而且有大量的 Go 程序员对现状表示满意。”
总结
目前 Go 错误处理的情况和困境是比较明确的,很多社区同学会基于以往已经被否决的旧提案上进行不断的微改,再不断提交。
现阶段都是被全面否定的,因为即使做了微调,也无法改变提案本身的核心思想。
而 Go 官方自己提出的 check/handle 和 try 提案,在社区中也被广大的网友否决了。还获得了史上最多人否决的提案的位置。
现阶段来看,未来 1-3 年内在错误处理的优化上仍然会继续僵持。