错误处理

概述

Go 语言采用独特的错误处理方式,通过返回值而非异常来处理错误。本部分将详细讲解 Go 语言的错误处理机制和最佳实践,帮助你编写健壮可靠的程序。

章节内容

27. 错误处理基础

Go 的错误处理是显式的,需要开发者主动检查。本章讲解:

  • error 接口
  • 创建错误
  • 错误检查
  • 错误信息格式化
  • 错误处理模式

28. 自定义错误与错误包装

自定义错误可以携带更多上下文信息。本章涵盖:

  • 自定义错误类型
  • errors.New 和 fmt.Errorf
  • 错误包装(%w)
  • errors.Is 和 errors.As
  • 错误链

29. 错误处理最佳实践

良好的错误处理是程序质量的重要保证。本章介绍:

  • 错误处理原则
  • 错误信息设计
  • 错误恢复策略
  • 日志记录
  • Panic 和 Recover

学习要点

基本错误处理

// 创建错误
err := errors.New("发生错误")
err2 := fmt.Errorf("操作失败: %s", reason)

// 检查错误
result, err := someFunction()
if err != nil {
    return err  // 向上传递
}

自定义错误

type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("验证错误 [%s]: %s", e.Field, e.Message)
}

// 使用
if name == "" {
    return &ValidationError{Field: "name", Message: "不能为空"}
}

错误包装

// 包装错误
if err != nil {
    return fmt.Errorf("保存用户失败: %w", err)
}

// 解包检查
if errors.Is(err, sql.ErrNoRows) {
    // 处理未找到
}

var validationErr *ValidationError
if errors.As(err, &validationErr) {
    // 处理验证错误
}

Panic 和 Recover

// Panic(仅用于不可恢复的错误)
panic("严重错误")

// Recover
defer func() {
    if r := recover(); r != nil {
        log.Printf("恢复: %v", r)
    }
}()

学习建议

  1. 显式处理错误:不要忽略任何错误返回值
  2. 提供上下文:错误信息应包含足够的上下文
  3. 早返回:使用早返回模式减少嵌套
  4. 合理使用 Panic:Panic 仅用于真正的异常情况
  5. 记录日志:在适当位置记录错误日志