模块 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。