跳转到主要内容
模块 6 · 第 5 课(共 5)课程中的30/50~14 min
模块课程(5/5)

错误接口

Go 中的 error 不是一个关键字:它是一个内置接口,带有 单一方法。

Go
type error interface {
    Error() string
}

任何具有 Error() string 的内容都是 error。结合 从函数返回 (T, error) 的约定,它是 Go 中错误处理的基础。

哨兵错误

Go
import "errors"

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

func find(key string) (string, error) {
    // ...
    return "", ErrNotFound
}

sentinel 是调用者可以导出的 error 值 进行比较以识别特定的错误情况。

自定义错误(带数据)

为了携带上下文(例如缺少的键),您定义一个类型:

Go
type ErrNotFound struct {
    Key string
}

func (e *ErrNotFound) Error() string {
    return "non trovato: " + e.Key
}

func find(key string) (string, error) {
    return "", &ErrNotFound{Key: key}
}

错误.Is 和错误.As (Go 1.13+)

与 == 相比仅适用于“纯”哨兵。保持稳健 针对包装错误,请使用 errors 包:

Go
import "errors"

if errors.Is(err, ErrNotFound) {
    // err IS ErrNotFound (even if wrapped)
}

var nfe *ErrNotFound
if errors.As(err, &nfe) {
    // err IS (or wraps) an *ErrNotFound; nfe points to the concrete value
    fmt.Println("chiave mancante:", nfe.Key)
}
  • errors.Is(err, target):如果目标位于包装链中的某个位置,则为 true。
  • errors.As(err, &target):分配目标其类型链中的第一个错误。

用 %w 换行

Go
if err := find("k"); err != nil {
    return fmt.Errorf("operazione X: %w", err)
}

%w(不是 %s 或 %v)创建一个新错误,包装 原始,通过 errors.Is/As 保持链可导航。

处理模式

Go
v, err := op()
if err != nil {
    return fmt.Errorf("op fallita per %q: %w", id, err)
}

成语:

  • 检查err != nil 立即,没有“早期快乐路径”。
  • 使用 fmt.Errorf("... : %w", err) 在每个级别添加上下文。
  • “上游”(靠近主/处理程序),通过 errors.Is/As 进行区分。

尝试一下

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

在 *ErrNotFound 上实现 Error() 字符串,使其返回“non trovato: <Key>”。

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

`fmt.Println(err)` 自动调用结构体上的 Error() 方法。

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

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

使用errors.Is检查err是否等于哨兵ErrVuoto。

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

即使使用包装链,“errors.Is(err, target)”也很强大。

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

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

实现错误的方法的确切签名是什么?

Go
func (e *MyErr) ??? {}
答案选项

回顾

  • error = interface { Error() string },内置。
  • 对于没有上下文的已知情况,带有 errors.New("...") 的哨兵。
  • 带有携带上下文的字段的自定义错误类型。
  • errors.Is(err, target):对包装比较稳健。
  • errors.As(err, &target):提取具体类型。
  • fmt.Errorf("...: %w", err):保护链条的包装。
  • 切勿使用 %v / %s 进行换行:始终使用 %w。