当前位置: 首页 > article >正文

第5章:Go语言错误处理和异常

第5章:Go语言错误处理和异常

5.1 错误类型基础

5.1.1 error接口

// error接口定义
type error interface {
    Error() string
}

// 自定义错误
type CustomError struct {
    Message string
    Code    int
}

func (e *CustomError) Error() string {
    return fmt.Sprintf("错误码: %d, 信息: %s", e.Code, e.Message)
}

5.1.2 创建和使用错误

// 创建简单错误
func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("除数不能为零")
    }
    return a / b, nil
}

func main() {
    result, err := divide(10, 0)
    if err != nil {
        fmt.Println("发生错误:", err)
        // 处理错误
    }
}

5.2 错误处理模式

5.2.1 多返回值错误处理

func readFile(filename string) ([]byte, error) {
    data, err := ioutil.ReadFile(filename)
    if err != nil {
        // 错误处理
        return nil, fmt.Errorf("读取文件失败: %v", err)
    }
    return data, nil
}

func processFile(filename string) {
    data, err := readFile(filename)
    switch {
    case err == nil:
        // 正常处理
        fmt.Println(string(data))
    case os.IsNotExist(err):
        fmt.Println("文件不存在")
    case os.IsPermission(err):
        fmt.Println("权限不足")
    default:
        fmt.Println("未知错误:", err)
    }
}

5.2.2 错误类型断言

type ValidationError struct {
    Field string
    Value interface{}
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("验证错误:字段 %s 值 %v 不合法", e.Field, e.Value)
}

func validateAge(age int) error {
    if age < 0 || age > 150 {
        return &ValidationError{
            Field: "Age",
            Value: age,
        }
    }
    return nil
}

func main() {
    err := validateAge(-5)
    if err != nil {
        if ve, ok := err.(*ValidationError); ok {
            fmt.Printf("特定错误处理:%s\n", ve.Error())
        }
    }
}

5.3 panic和recover

5.3.1 panic触发

func riskyOperation() {
    panic("发生严重错误")
}

func main() {
    riskyOperation()  // 程序将立即终止
}

5.3.2 recover捕获异常

func recoverExample() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("捕获到panic:", r)
            // 可以进行日志记录、资源清理等
        }
    }()

    // 模拟可能发生panic的代码
    panic("unexpected error")
}

func main() {
    recoverExample()
    fmt.Println("程序继续执行")
}

5.4 自定义错误处理

5.4.1 错误包装

func wrapError(err error) error {
    return fmt.Errorf("操作失败:%w", err)
}

func complexOperation() error {
    // 模拟底层错误
    baseErr := errors.New("数据库连接失败")
    return wrapError(baseErr)
}

func main() {
    err := complexOperation()
    
    // 错误解包
    if errors.Is(err, baseErr) {
        fmt.Println("匹配到原始错误")
    }
}

5.4.2 错误日志记录

type Logger struct {
    file *os.File
}

func (l *Logger) LogError(err error) {
    if err != nil {
        logEntry := fmt.Sprintf("%s - Error: %v\n", 
            time.Now().Format(time.RFC3339), err)
        l.file.WriteString(logEntry)
    }
}

func main() {
    logger, _ := os.OpenFile("error.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    defer logger.Close()

    customLogger := &Logger{file: logger}
    
    err := someRiskyOperation()
    customLogger.LogError(err)
}

5.5 最佳实践

5.5.1 错误处理原则

  1. 始终检查错误
  2. 只处理可以处理的错误
  3. 在合适的抽象层级传播错误
  4. 避免忽略错误
  5. 使用错误包装增加上下文信息

5.5.2 常见错误处理模式

// 错误处理模式示例
func processData(data []byte) error {
    if len(data) == 0 {
        return errors.New("数据为空")
    }

    // 处理数据的复杂逻辑
    return nil
}

func main() {
    data := []byte{}
    if err := processData(data); err != nil {
        log.Printf("处理失败:%v", err)
        // 根据不同错误类型采取不同处理策略
        return
    }
}

实践项目:简单的配置文件解析器

type Config struct {
    Database struct {
        Host string
        Port int
    }
}

func parseConfig(filename string) (*Config, error) {
    data, err := ioutil.ReadFile(filename)
    if err != nil {
        return nil, fmt.Errorf("读取配置文件失败: %w", err)
    }

    var config Config
    if err := json.Unmarshal(data, &config); err != nil {
        return nil, fmt.Errorf("解析配置文件失败: %w", err)
    }

    return &config, nil
}

func main() {
    config, err := parseConfig("config.json")
    if err != nil {
        switch {
        case os.IsNotExist(err):
            log.Fatal("配置文件不存在")
        case os.IsPermission(err):
            log.Fatal("无权限读取配置文件")
        default:
            log.Fatalf("配置解析错误: %v", err)
        }
    }

    fmt.Printf("数据库配置:%+v\n", config.Database)
}

http://www.kler.cn/a/470262.html

相关文章:

  • Python连接和操作Elasticsearch详细指南
  • 网络层协议之IP数据包层分片随笔
  • 谷歌浏览器的书签同步功能详解
  • 51单片机——8*8LED点阵
  • 用公网服务代理到本地电脑笔记
  • node.js内置模块之---http 和 https 模块
  • 【LeetCode】:稀疏相似度【困难】
  • 多线程+Condition 对象模拟生产者/消费者问题
  • 【亲测有效】Kafka3.5.0分布式集群安装部署与测试-最新
  • 带内管理和带外管理
  • 【ACM出版 | 高录用 |快检索】2025年第二届机器学习与神经网络国际学术会议(MLNN 2025)
  • 前后端分离架构设计与实现:构建现代Web应用的基石
  • 《机器学习》——逻辑回归(过采样)
  • 机器翻译
  • [ECCV 2018]Receptive Field Block Net for Accurate and Fast Object Detection
  • 【python如何使用随机模块】
  • RabbitMQ端口操作
  • 相机镜头竞品选型的主要参考参数和选型方法
  • 第4章:Go语言面向对象编程
  • 下载b站高清视频
  • 字玩FontPlayer开发笔记8 Tauri2文件系统
  • Opencv查找、绘制轮廓、圆形矩形轮廓和近似轮廓
  • ffmpeg八大开发库
  • 深入理解 pytest_runtest_makereport:如何在 pytest 中自定义测试报告
  • OKHttp调用第三方接口,响应转string报错okhttp3.internal.http.RealResponseBody@4a3d0218
  • 平安产险安徽分公司携手安徽中医药临床研究中心附属医院 共筑儿童安全防护网