编程Go开发者

Go中的错误处理是如何工作的:有哪些处理方法,为什么错误通常被返回而不是抛出,以及如何实现自定义错误类型?

用 Hintsage AI 助手通过面试

答案。

在Go中,处理错误的标准方法是从函数中返回error类型的值。与具有异常的语言不同,在Go中,异常(panicrecover)仅用于真正的特殊情况;对于业务逻辑,应使用普通错误。

经典方式:

func doSomething() error { // ... return nil // 或者 errors.New("some error") } err := doSomething() if err != nil { // 处理错误 }

您可以创建自定义错误类型以进行更详细的分析:

type MyError struct { Code int Message string } func (e *MyError) Error() string { return fmt.Sprintf("(%d) %s", e.Code, e.Message) } err := &MyError{404, "not found"}

典型的具体错误检查:

if myErr, ok := err.(*MyError); ok && myErr.Code == 404 { // 处理404错误 }

陷阱问题。

在Go中可以使用==将error与nil比较吗?

答案: 可以并且应该这样做,以检查是否没有错误。但重要的是要记住:如果错误被包装或使用包含nil的结构创建,则比较可能是错误的。例如:

var err error = (*MyError)(nil) fmt.Println(err == nil) // false!

错误发生是因为如果接口的类型不是nil,则该接口不等于nil,即使内部值是nil。

由于对该主题细节的不了解而产生的实际错误示例。


故事

一个微服务通过与nil比较来记录错误。其中一位开发人员返回了像(*MyError)(nil)这样的类型化错误,未注意到这并不等同于nil(接口不是nil)。结果,错误处理停止工作,许多虚假警报进入了指标。


故事

在项目中,未通过链传递错误,而是对所有错误使用panic,认为这是“干净”的方式。这导致每次用户输入无效时应用程序崩溃,因为panic/recover并不适用于流业务逻辑。


故事

错误被多次使用fmt.Errorf("some: %w", err)包装,而在检查特定类型的错误时进行了普通比较,而没有使用errors.Iserrors.As。这导致业务逻辑没有对自定义错误类型做出反应,即使它们实际上存在于包装的错误内部。