Go 把 error 当普通值处理:函数最后一个返回值返回 error,调用方显式检查。最佳实践包括:错误向上传递时用 fmt.Errorf 加 %w 包装上下文,形成错误链;只在能处理或能补充有意义信息的层级处理错误,避免'记录后又返回'的双重处理;哨兵错误(如 io.EOF、sql.ErrNoRows)用 errors.Is 判断,自定义错误类型用 errors.As 提取。

var ErrNotFound = errors.New("not found")

type PermissionError struct{ User string }
func (e *PermissionError) Error() string { return "deny: " + e.User }

err := process()
if errors.Is(err, ErrNotFound) { /* 哨兵判断 */ }
var pe *PermissionError
if errors.As(err, &pe) { fmt.Println(pe.User) } // 类型提取

关键点:%w 与 %v 的区别是前者可被 Is/As 穿透,后者只是字符串拼接;判断时必须用 errors.Is 而不是 ==(包装链上 == 失效);errors.Join(Go 1.20)可聚合多个错误。panic 只留给真正的不可恢复场景,库代码应返回 error。追问方向:错误链 Unwrap 机制、Opaque errors 风格、与异常体系的对比。