Loading...
Loading...
Compare original and translation side by side
errors.New("message")fmt.Errorf("doing X: %w", err)varerror%werrors.New("message")fmt.Errorf("doing X: %w", err)varerror%wvar// ✅ Good — exported sentinel error
var (
ErrNotFound = errors.New("user: not found")
ErrUnauthorized = errors.New("user: unauthorized")
)
// Naming convention: Err + Description
// Prefix with package context in the messageerrors.Isif errors.Is(err, user.ErrNotFound) {
// handle not found
}==errors.Is()var// ✅ 规范做法 — 导出的哨兵错误
var (
ErrNotFound = errors.New("user: not found")
ErrUnauthorized = errors.New("user: unauthorized")
)
// 命名约定:Err + 描述信息
// 消息中添加包上下文前缀errors.Isif errors.Is(err, user.ErrNotFound) {
// 处理未找到场景
}==errors.Is()type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation: field %s: %s", e.Field, e.Message)
}
// Callers extract with errors.As:
var valErr *ValidationError
if errors.As(err, &valErr) {
log.Printf("invalid field: %s", valErr.Field)
}type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation: field %s: %s", e.Field, e.Message)
}
// 调用方使用errors.As提取:
var valErr *ValidationError
if errors.As(err, &valErr) {
log.Printf("invalid field: %s", valErr.Field)
}%w// ✅ Good — context added, chain preserved
func getUser(id int64) (*User, error) {
row, err := db.QueryRow(ctx, query, id)
if err != nil {
return nil, fmt.Errorf("get user %d: %w", id, err)
}
// ...
}
// ❌ Bad — no context
return nil, err
// ❌ Bad — chain broken, callers can't errors.Is/As
return nil, fmt.Errorf("failed: %v", err)%w// ✅ 规范做法 — 添加上下文,保留错误链
func getUser(id int64) (*User, error) {
row, err := db.QueryRow(ctx, query, id)
if err != nil {
return nil, fmt.Errorf("get user %d: %w", id, err)
}
// ...
}
// ❌ 错误做法 — 无上下文
return nil, err
// ❌ 错误做法 — 错误链中断,调用方无法使用errors.Is/As
return nil, fmt.Errorf("failed: %v", err)%w%w%v%w// Intentionally hiding internal DB error from public API
return nil, fmt.Errorf("user lookup failed: %v", err)%v%w// 有意向公共API隐藏内部数据库错误
return nil, fmt.Errorf("user lookup failed: %v", err)// ✅ Good — return the error, let caller decide
func loadConfig(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("load config %s: %w", path, err)
}
// ...
}
// ❌ Bad — log AND return (error handled twice)
func loadConfig(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
log.Printf("failed to read config: %v", err) // handled once
return nil, err // handled again
}
// ...
}// ✅ 规范做法 — 返回错误,由调用方决定处理方式
func loadConfig(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("load config %s: %w", path, err)
}
// ...
}
// ❌ 错误做法 — 既记录日志又返回(错误被处理两次)
func loadConfig(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
log.Printf("failed to read config: %v", err) // 第一次处理
return nil, err // 第二次处理
}
// ...
}// Sentinel errors: Err prefix
var ErrNotFound = errors.New("not found")
// Error types: Error suffix
type NotFoundError struct { ... }
type ValidationError struct { ... }
// Error messages: lowercase, no punctuation, no "failed to" prefix
// Include context: "package: action: detail"
errors.New("auth: token expired")
fmt.Errorf("user: get by id %d: %w", id, err)// 哨兵错误:以Err为前缀
var ErrNotFound = errors.New("not found")
// 错误类型:以Error为后缀
type NotFoundError struct { ... }
type ValidationError struct { ... }
// 错误消息:小写,无标点,无"failed to"前缀
// 包含上下文:"包名: 操作: 详情"
errors.New("auth: token expired")
fmt.Errorf("user: get by id %d: %w", id, err)template.Mustt.Fatalt.FailNowpanictemplate.Mustt.Fatalt.FailNowpanic// Inline error check — preferred for simple cases
if err := doSomething(); err != nil {
return fmt.Errorf("do something: %w", err)
}
// Multi-return with named result — acceptable for complex functions
func process() (result string, err error) {
defer func() {
if err != nil {
err = fmt.Errorf("process: %w", err)
}
}()
// ...
}
// errors.Join for multiple errors (Go 1.20+)
var errs []error
for _, item := range items {
if err := validate(item); err != nil {
errs = append(errs, err)
}
}
return errors.Join(errs...)// 内联错误检查 — 简单场景首选
if err := doSomething(); err != nil {
return fmt.Errorf("do something: %w", err)
}
// 带命名返回值的多返回 — 复杂函数可接受
func process() (result string, err error) {
defer func() {
if err != nil {
err = fmt.Errorf("process: %w", err)
}
}()
// ...
}
// errors.Join用于多错误处理(Go 1.20+)
var errs []error
for _, item := range items {
if err := validate(item); err != nil {
errs = append(errs, err)
}
}
return errors.Join(errs...)_fmt.Errorf%w%vvar Err...errorerrors.Iserrors.As==_fmt.Errorf%w%vvar Err...errorerrors.Iserrors.As==