提案:内置的Go错误检查功能, try

该提案已经结束。谢谢大家,感谢您的投入。

在评论之前,请阅读详细的设计文档,并查看截至6月6日的摘要,截至6月10日的摘要最重要的是关于保持专注建议。您的问题或建议可能已经得到解答或提出。谢谢。

我们提出了一个新的内置函数try,专门用于消除if通常与Go中的错误处理相关的样板语句。建议不要更改其他语言。我们提倡使用现有defer语句和标准库函数来帮助扩充或包装错误。这种最小化的方法可以解决大多数常见情况,同时为语言增加很少的复 该try内置很容易解释,直接实现的,垂直的其它语言结构,并完全向后兼容。如果我们希望将来这样做,它还为扩展机制留下了开辟的道路。

[以下文字已经过编辑,可以更准确地反映设计文档。]

try内置函数采用一个单一表达式作为参数。表达式必须求值为n + 1个值(其中n可能为零),其中最后一个值必须是type error。如果(final)error参数为nil,则返回前n个值(如果有),否则返回带有该错误的封闭函数。例如,代码如

f,错误 := os。打开(文件名)
 if err!= nil {
	 return ...,err   //其他结果的零值,如果有的话 
}

可以简化为

f  :=  try(os。打开(文件名))

try只能在自身返回error结果的函数中使用,并且该结果必须是封闭函数的最后一个结果参数。

该提案将去年GopherCon中提出的原始设计草案简化为其本质。如果需要错误扩充或包装,有两种方法:坚持使用久经考验的if语句,或者,使用语句“声明”错误处理程序defer

defer  func(){
	 if err!= nil {	 //可能没有发生错误 - 检查 
		错误= ...	 // wrap / augment error 
	} 
}()

这里 err是封闭函数的错误结果的名称。在实践中,合适的辅助函数将减少错误处理程序对单行程序的声明。例如

延迟 fmt。HandleErrorf(&err,“ copy %s  %s ”,src,dst)

fmt.HandleErrorf装饰*err)读得很好,可以在不需要新语言功能的情况下实现。

这种方法的主要缺点是需要命名错误结果参数,可能导致不太漂亮的API。最终这是一个风格问题,我们相信我们会适应期待新风格,就像我们适应没有分号一样。

总而言之,一开始try可能看起来很不寻常,但它只是针对一个特定任务量身定制的语法糖,错误处理用较少的样板,并且足够好地处理该任务。因此,它非常符合Go的哲学。try不是为解决所有错误处理情况而设计的; 它旨在很好地处理最常见的情况,以保持设计简单明了。

积分

该提议受到我们迄今收到的反馈的强烈影响。具体来说,它借鉴了以下方面的想法

VojtechVitek** 评论道

我觉得try()已经表达了反对该提案的所有重要反馈意见。但让我试着总结一下:

  1. try()将垂直代码复杂度移动到水平
  2. 嵌套的try()调用与三元运算符一样难以阅读
  3. 引入不可视的“返回”控制流,这种控制流在视觉上并不明显(与以return关键字开头的缩进块相比)
  4. 使错误包装实践更糟糕(函数的上下文而不是特定的操作)
  5. 拆分#golang社区和代码风格(反gofmt)
  6. 将使devs重写try()到if-err-nil,反之亦然(tryhard与添加清理逻辑/附加日志/更好的错误上下文)

iand

@VojtechVitek 我认为你提出的观点是主观的,只有在人们开始认真对待它时才能评估。

但是我认为有一个技术问题没有得到太多讨论。使用的模式defer错误包装/装饰已经超越简单的性能价格比的影响defer,因为使用功能本身defer不能被内联。

这意味着tryerr != nil检查后直接返回包装错误相比,采用错误包装会产生两个潜在成本:

  1. 通过函数的所有路径的延迟,甚至是成功的路径
  2. 丢失内联

即使有一些令人印象深刻的即将到来的性能改进,defer成本仍然不为零。

try具有很大的潜力所以如果Go团队可以重新考虑设计以允许在故障点进行某种包装而不是先发制人通过,这将是很好的defer

格里塞默

嗨,大家好,

我们与此类提案的目标是在社群范围内讨论影响,权衡和如何继续,然后使用该讨论来帮助确定前进的道路。

基于压倒性的社区反应和广泛的讨论,我们正在提前宣布该提案被拒绝。

就技术反馈而言,本次讨论有助于确定我们错过的一些重要注意事项,尤其是添加调试打印和分析代码覆盖率的影响。

更重要的是,我们清楚地听到许多人认为这个提案不是针对一个有价值的问题。我们仍然认为Go中的错误处理并不完美,可以进行有意义的改进,但很明显,作为一个社区,我们需要更多地讨论错误处理的具体方面是我们应该解决的问题。

至于讨论要解决的问题,我们试图在去年8月的“ Go 2错误处理问题概述 ”中阐述我们对问题的看法,但回想起来,我们没有引起足够的注意力,并且没有足够的鼓励讨论具体问题是否正确。该try提案可能是解决该问题的一个很好的解决方案,但对于你们中的许多人来说,这根本不是一个需要解决的问题。在未来,我们需要更好地吸引对这些早期问题陈述的关注,并确保对需要解决的问题达成广泛共识。

(通过在同一天发布泛型设计草案,错误处理问题陈述也可能完全被提升。)

关于Go错误处理有哪些改进的更广泛的主题,我们非常高兴看到有关Go中错误处理的哪些方面在您自己的代码库和工作环境中对您来说最有问题的经验报告以及一个好的解决方案会产生多大影响有你自己的发展。如果你确实写了这样的报告,请在Go2ErrorHandlingFeedback页面上发布一个链接。

感谢参与此次讨论的所有人,无论是在这里还是其他地方。正如Russ Cox之前所指出的那样,像这样的社区范围内的讨论是最好的开源。我们非常感谢大家帮助我们检查这个特定的提案,更普遍的是讨论改善Go中错误处理状态的最佳方法。

罗伯特格里塞默,提案审查委员会。