> ## Content Index
> Fetch the complete content index at: https://huizhou92.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Go 中的错误处理:新的?运算符
- URL: https://huizhou92.com/streamlining-error-handling-in-go-exploring-the-new-proposal/
- Published: 2025-01-11T11:35:01.000Z
- Updated: 2026-09-06T11:39:52.000Z
- Description: Go 中的错误处理:新的?运算符. 背景 错误处理一直是编程中的重要组成部分, Go语言因为它独特的错误处理模式饱受争议，任何一篇写如何讨厌Go语言的博客中，一定会把“繁琐的错误处理”放在靠前的位置。这个问题在 Go 社区引发了大量讨论，探讨如何在保持清晰性和可维护性的同时减少模板代码。 Proposal 详。
- Author: huizhou92
- Tags: tech, golang, #lang-zh-cn

## 背景

错误处理一直是编程中的重要组成部分, Go语言因为它独特的错误处理模式饱受争议，任何一篇写如何讨厌Go语言的博客中，一定会把“繁琐的错误处理”放在靠前的位置。这个问题在 Go 社区引发了大量讨论，探讨如何在保持清晰性和可维护性的同时减少模板代码。  
![在我自己的一个项目中，有 422 个  ](https://images.hxzhouh.com/blog-images/2025/01/18bc60f984a1841e69691ce05edfb655.webp)

## Proposal 详情

[ianlancetaylor](https://github.com/ianlancetaylor?ref=huizhou92.com)提出了一个新的提案[#71203](https://github.com/golang/go/issues/71203?ref=huizhou92.com) ,在 Go 中引入用于错误处理的操作符`?`。用来简化Go的错误处理。后续Go的错误处理可能会变成这个样子:

```go
// now
result, err := someFunction()
if err != nil {
    return nil, err
}
// proposal ? 
result := someFunction()?

```

在本例中，两种写法的结果是相等的：如果 `someFunction()`返回错误，就返回。  
这个proposal的 核心内容就是这样了, 主要目的是减少templ代码，同时保持 Go 的显式和简洁理念。`？`是一个语法糖，在返回多个值的函数调用（例如 `(T, error)`）之后使用时，它会自动检查最后一个值是否为非零（表示错误)。编译器将为 这种写法生成跟以前一样的代码，保证兼容性。  
在正式提案中，[ianlancetaylor](https://github.com/ianlancetaylor?ref=huizhou92.com)详细阐述了`?`的语法规则：

- `?`只能出现在赋值语句或表达式语句的末尾，并且表达式必须要有返回值
- 对于表达式语句，`?`“吸收”的是表达式的最后一个值（通常是err）
- 对于赋值语句，`?`“吸收”的是右侧表达式的最后一个值（通常是err），这样右侧值的数量会比左侧变量的数量多一个。
- 这个被“吸收”的值称为qvalue, 必须是实现了error接口的接口类型。
- `?`后面可以跟一个代码块。如果没有代码块，当qvalue不为nil时，函数会立即返回，并将qvalue赋给最后一个返回值。如果`?`后面有代码块，当qvalue不为nil时，代码块会被执行。在代码块中，会**隐式声明**一个名为err的变量，其值和类型与qvalue相同。

基本的使用场景可能是这样子的:

```go

r := os.Open("file.txt") ? // ? 吸收了  os.Open 的error, 如果不为空，就会返回。

func Run() error { 
	Start() ? // 如果 Start 返回非 nil 的 error，立即返回该 error 
	return nil 
}

func process() error {
	result := doSomething() ? {
		return fmt.Errorf("something failed: %v", err)  // qvalue 
	}
	anotherResult := doAnotherThing(result)?
	return nil
}

```

## 优点

这个 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](https://github.com/golang/go/issues/68391?ref=huizhou92.com) 等不同的是, `?` 不会引入隐藏的控制流, `?`的存在明确地指示了错误处理的逻辑。

## 缺点

最大的缺点就是所有的Go图书、资料需要更新，并且对于新人来说，可能需要理解这个概念，因为它跟其他语言的实现都不太一样。并且这个改动，会涉及很多代码，包括go src，所以`Go Core Team` 的压力也很大，因为机会只有一次。

### Err 是隐式变量

`?`后面的代码块会隐式声明一个err变量，这可能会导致变量shadowing的问题。 proposal 中提到了一个例子，

```go
for n = 1; !utf8.FullRune(r.buf[:n]); n++ {
	r.buf[n], err = r.readByte()
	if err != nil {
		if err == io.EOF {
			err = nil // must change outer err
			break
		}
		return
	}
}
// code that later returns err

```

> In this example, the assignment `err = nil` has to change the `err` variable that exists outside of the `for` loop. Using the `?` operator would introduce a new `err` variable shadowing the outer one.  
> In this example, using the `?` operator would cause a compiler error because the assignment `err = nil` would set a variable that is never used.

> 在这个例子中，赋值 `err = nil` 必须改变存在于 `for` 循环之外的 `err` 变量。如果使用 `?` 操作符，就会引入一个新的 `err` 变量，遮蔽外部变量。  
> 在本例中，使用 `?` 操作符还会导致编译器错误，因为赋值 `err = nil` 会设置一个从未使用过的变量。

### 写代码的心智负担会增加

```go
func F1() error {
	err := G1()
	log.Print(err)
	G2() ?
	{
		log.Print(err)
	}
	return nil
}

func F2() error {
	err := G1()
	log.Print(err)
	G2() ? {
		log.Print(err)
	}
	return nil
}

```

在这个例子中，这两个函数都合法，只有G2的换行符有差异，但它们的行为却完全不同。 这个差异可不能通过fmt等方式找补回来。

### 不改变的合理性

尽管Go的错误处理机制经常受到批评，但它仍然是可用的。因此，社区需要权衡是否真的需要进行改变。在proposal中，[ianlancetaylor](https://github.com/ianlancetaylor?ref=huizhou92.com)反复提到: "**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语言的错误处理机制提供了一种新的思路。该提案通过引入简洁的语法，可以显著减少错误处理的代码量，并使代码的主流程更加清晰。尽管现在还存在一些分歧，但是总算有人在推动不是？

---

- [本文长期连接](https://huizhou92.com/streamlining-error-handling-in-go-exploring-the-new-proposal)
- 如果您觉得我的博客对你有帮助，请通过 [RSS](https://huizhou92.com/sitemap.xml)订阅我。
- 或者在[X](https://x.com/@piaopiaopig?ref=huizhou92.com)上关注我。
- 如果您有[Medium](https://medium.huizhou92.com/?ref=huizhou92.com)账号，能给我个关注嘛？我的文章第一时间都会发布在Medium。