提案:将抛出作为Go语言中自动错误传播的特殊变量
提案:通过 `throw` 标识符在 Go 中隐式错误传播
<p>摘要</p>
本提案引入了一种新的语法约定:在变量声明或赋值中使用标识符 `throw`(例如,`result, throw := errorFunc()`)。当编译器检测到这一用法时,将自动插入对非零错误的检查,并返回所有非错误返回值的零值以及错误。这一机制简化了错误处理,同时不妨碍 Go 语言一贯的明确性和可读性。
<p>动机</p>
Go 鼓励显式的错误处理,这常常导致重复的样板代码。例如:
<p>result, err := errorFunc()
if err != nil {
return zeroValue, err
}</p>
这种模式虽然清晰,但增加了冗长性,可能会影响可读性,尤其是在包含多个易出错调用的函数中。通过引入一种保留清晰度的语法简写,我们可以减少样板代码,提高开发者的工作效率。
<p>提案</p>
当一个名为 `throw` 的变量被赋值为返回 `error` 的函数的结果,并且外层函数返回一个 `error` 时,编译器将隐式插入:
<p>if throw != nil {
return zeroValues..., throw
}</p>
<p>适用场景</p>
短声明:
<pre><code> x, throw := doSomething()
</code></pre>
标准赋值:
<pre><code> x, throw = doSomething()
</code></pre>
带赋值的变量声明:
<pre><code> var x T; var throw error; x, throw = doSomething()
</code></pre>
* `throw` 必须是 `error` 类型的变量
* 外层函数必须返回一个 `error`
* 该规则仅适用于变量名明确为 `throw` 的情况
<p>示例</p>
传统错误处理:
<pre><code>func getUserData(id int) (data Data, err error) {
data, err := fetch(id)
if err != nil {
return Data{}, err
}
return data, nil
}</code></pre>
使用 `throw`:
<pre><code>func getUserData(id int) (Data, error) {
data, throw := fetch(id)
// 自动扩展为:if throw != nil { return Data{}, throw }
moreData, throw := fetchMore(id)
// 自动扩展为:if throw != nil { return Data{}, throw }
return data, nil
}</code></pre>
查看原文
Proposal: Implicit Error Propagation via `throw` Identifier in Go<p>Abstract<p>This proposal introduces a new syntactic convention to Go: the use of the identifier `throw` in variable declarations or assignments (e.g., `result, throw := errorFunc()`). When detected, the compiler will automatically insert a check for a non-nil error and return zero values for all non-error return values along with the error. This mechanism streamlines error handling without compromising Go's hallmark of explicit, readable code.<p>Motivation<p>Go encourages explicit error handling, which often results in repetitive boilerplate code. For example:<p>result, err := errorFunc()
if err != nil {
return zeroValue, err
}<p>This pattern, while clear, adds verbosity that can hinder readability, especially in functions with multiple error-prone calls. By introducing a syntactic shorthand that preserves clarity, we can reduce boilerplate and improve developer ergonomics.<p>Proposal<p>When a variable named `throw` is assigned the result of a function returning an `error`, and the enclosing function returns an `error`, the compiler will implicitly insert:<p>if throw != nil {
return zeroValues..., throw
}<p>Applicable Scenarios<p>Short declarations:<p><pre><code> x, throw := doSomething()
</code></pre>
Standard assignments:<p><pre><code> x, throw = doSomething()
</code></pre>
Variable declarations with assignment:<p><pre><code> var x T; var throw error; x, throw = doSomething()
</code></pre>
* `throw` must be a variable of type `error`<p>* The surrounding function must return an `error`<p>* The rule only applies when the variable is explicitly named `throw`<p>Example<p>Traditional Error Handling<p>func getUserData(id int) (data Data, err error) {
data, err := fetch(id)
if err != nil {
return Data{}, err
}
return data, nil
}<p>With `throw`<p>func getUserData(id int) (Data, error) {<p><pre><code> data, throw := fetch(id)
// Automatically expands to: if throw != nil { return Data{}, throw }
moreData, throw := fetchMore(id)
// Automatically expands to: if throw != nil { return Data{}, throw }
return data, nil
}</code></pre>