背景
错误处理一直是编程中的重要组成部分, Go语言因为它独特的错误处理模式饱受争议,任何一篇写如何讨厌Go语言的博客中,一定会把“繁琐的错误处理”放在靠前的位置。这个问题在 Go 社区引发了大量讨论,探讨如何在保持清晰性和可维护性的同时减少模板代码。
Proposal 详情
ianlancetaylor提出了一个新的提案#71203 ,在 Go 中引入用于错误处理的操作符?
。用来简化Go的错误处理。后续Go的错误处理可能会变成这个样子:
|
|
在本例中,两种写法的结果是相等的:如果 someFunction()
返回错误,就返回。
这个proposal的 核心内容就是这样了, 主要目的是减少templ代码,同时保持 Go 的显式和简洁理念。?
是一个语法糖,在返回多个值的函数调用(例如 (T, error)
)之后使用时,它会自动检查最后一个值是否为非零(表示错误)。编译器将为 这种写法生成跟以前一样的代码,保证兼容性。
在正式提案中,ianlancetaylor详细阐述了?
的语法规则:
?
只能出现在赋值语句或表达式语句的末尾,并且表达式必须要有返回值- 对于表达式语句,
?
“吸收”的是表达式的最后一个值(通常是err) - 对于赋值语句,
?
“吸收”的是右侧表达式的最后一个值(通常是err),这样右侧值的数量会比左侧变量的数量多一个。 - 这个被“吸收”的值称为qvalue, 必须是实现了error接口的接口类型。
?
后面可以跟一个代码块。如果没有代码块,当qvalue不为nil时,函数会立即返回,并将qvalue赋给最后一个返回值。如果?
后面有代码块,当qvalue不为nil时,代码块会被执行。在代码块中,会隐式声明一个名为err的变量,其值和类型与qvalue相同。
基本的使用场景可能是这样子的:
|
|
优点
这个 proposal 最重要(也是唯一的好处)好处是减少 Go 程序中的重复代码数量, 根据proposal 中的描述.
reduces the error handling boilerplate from 9 tokens to 5, 24 non-whitespace characters to 12, and 3 boilerplate lines to 2.
跟以前的错误处理提案try 等不同的是, ?
不会引入隐藏的控制流, ?
的存在明确地指示了错误处理的逻辑。
缺点
最大的缺点就是所有的Go图书、资料需要更新,并且对于新人来说,可能需要理解这个概念,因为它跟其他语言的实现都不太一样。并且这个改动,会涉及很多代码,包括go src,所以Go Core Team
的压力也很大,因为机会只有一次。
Err 是隐式变量
?
后面的代码块会隐式声明一个err变量,这可能会导致变量shadowing的问题。 proposal 中提到了一个例子,
|
|
In this example, the assignment
err = nil
has to change theerr
variable that exists outside of thefor
loop. Using the?
operator would introduce a newerr
variable shadowing the outer one.
In this example, using the?
operator would cause a compiler error because the assignmenterr = nil
would set a variable that is never used.
在这个例子中,赋值
err = nil
必须改变存在于for
循环之外的err
变量。如果使用?
操作符,就会引入一个新的err
变量,遮蔽外部变量。
在本例中,使用?
操作符还会导致编译器错误,因为赋值err = nil
会设置一个从未使用过的变量。
写代码的心智负担会增加
|
|
在这个例子中,这两个函数都合法,只有G2的换行符有差异,但它们的行为却完全不同。 这个差异可不能通过fmt等方式找补回来。
不改变的合理性
尽管Go的错误处理机制经常受到批评,但它仍然是可用的。因此,社区需要权衡是否真的需要进行改变。在proposal中,ianlancetaylor反复提到: “Perhaps no change is better than this change. Perhaps no change is better than any change"。这也一定程度上反映出Go Core Team
在错误处理改进方面其实并不那么坚定,感觉更多是迫于Go社区的舆论和压力。
泛型: 别Q我
总结
新的proposal可以看出Go Core Team
还是在听社区的声音。?
操作符提案为Go语言的错误处理机制提供了一种新的思路。该提案通过引入简洁的语法,可以显著减少错误处理的代码量,并使代码的主流程更加清晰。尽管现在还存在一些分歧,但是总算有人在推动不是?