跳转到主要内容
模块 2 · 第 5 课(共 5)课程中的10/50~12 min
模块课程(5/5)

错误:“if err != nil”模式

在 Go 中,错误是值,而不是异常。一个函数可以 失败返回错误作为最后一个值,调用者检查它 明确地。它是明确的、可预测的、易于测试的——价格是 更冗长一点。

error 接口

error 是语言内置的一个小接口:

Go
type error interface {
    Error() string
}

任何实现 Error() string 的类型都是 error。

基本模式

Go
v, err := operazione()
if err != nil {
    // gestisci o propaga
    return err
}
// usa v

您将看到这一点数千次:这是每个人的惯用代码 容易出错的电话。不要对重复感到内疚——这是一个功能,而不是 一个错误。

构建错误:errors.New 和 fmt.Errorf

Go
import (
    "errors"
    "fmt"
)

err1 := errors.New("file mancante")
err2 := fmt.Errorf("apertura %q fallita: permesso negato", path)

当您想在消息中包含变量时,fmt.Errorf 是完美的选择。

用 %w 包装

要传播错误添加上下文而不丢失原始内容:

Go
f, err := os.Open(path)
if err != nil {
    return fmt.Errorf("config: %w", err)
}

%w “包装”原始错误,稍后可以使用 errors.Is (哨兵相等)或 errors.As (对于具体类型):

Go
if errors.Is(err, os.ErrNotExist) {
    // file inesistente, gestione speciale
}

哨兵错误

这些是作为变量导出的错误,用于与 errors.Is 进行比较:

Go
var ErrNotFound = errors.New("non trovato")

func find(id int) (Item, error) {
    // ...
    return Item{}, ErrNotFound
}

// chiamante:
if errors.Is(err, ErrNotFound) { ... }

panic 和 recover (预览)

panic 存在于 Go 中,但保留用于 不可恢复 错误(例如 bug、 违反了不变量),不适用于正常控制流。我们将更深入地 具有 defer/recover 的函数模块。现在:不要在适当的地方使用它 if err != nil 模式的。

尝试一下

锻炼#go.m2.l5.e1
尝试:0加载中...

处理来自 strconv.Atoi 的错误:如果 err != nil,则打印并返回;否则打印n。

正在加载编辑器...
显示提示

规范模式:检查 `err != nil`,记录/返回,然后使用 `n`。

3 次尝试后可用的解决方案

锻炼#go.m2.l5.e2
尝试:0加载中...

实现 safeDiv:如果 b == 0 返回 0 和错误。New('divisione per Zero');否则 a/b 和 nil。

正在加载编辑器...
显示提示

在除法之前检查 `b == 0` 以避免运行时恐慌。

3 次尝试后可用的解决方案

Quiz#go.m2.l5.e3
准备好

Go 中处理错误的惯用模式是什么?

Go
v, err := f()
// poi?
答案选项

回顾

  • error 是一个具有一种方法 Error() string 的接口。
  • 规范模式:v, err := f(); if err != nil { return err }。
  • 使用 errors.New(msg) 或 fmt.Errorf("ctx: %w", err) 构建错误。
  • 使用 %w 进行包装,并使用 errors.Is / errors.As 检查链条。
  • panic 仅适用于不可恢复的错误,不适用于正常控制流。