第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)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/949404.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++Primer const限定符

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

C语言 游动的小球

代码如下&#xff1a; 在这里插入代码片#include<stdio.h> #include<stdlib.h> #include<windows.h>int main() {int i,j;int x 5;int y 10;int height 20;int velocity_x 1;int velocity_y 1;int left 0;int right 20;int top 0;int bottom 10;while(1){…

动漫推荐系统django+vue前台后台完整源码

完整源码项目包获取→点击文章末尾名片&#xff01;

Chapter 1 Understanding Large Language Models

文章目录 Understanding Large Language ModelsWhat is an LLM?Applications of LLMSStages of building and using LLMsUsing LLMS for different tasksA closer look at the GPT architectureBuilding a large language modelSummary Understanding Large Language Models …

什么是VLAN?

VLAN&#xff08;Virtual Local Area Network&#xff0c;虚拟局域网&#xff09;是一种将物理局域网划分成多个逻辑上独立的虚拟网络的技术。VLAN不依赖于设备的物理位置&#xff0c;而是通过逻辑划分&#xff0c;将局域网内的设备虚拟地组织到同一组。这种技术允许网络管理员…

【君正T31开发记录】12.编译工具相关总结及介绍

移植交叉工具包的时候&#xff0c;发现这是很多工具的集合包&#xff1b;以及写makefile的时候&#xff0c;也需要了解下这些工具的作用及用法&#xff0c;这里总结记录一下常见的工具及相关用法。 g C编译器&#xff0c;用于编译C源代码文件&#xff0c;这个很常见&#xff0…

Appium(一)--- 环境搭建

一、Android自动化环境搭建 1、JDK 必须1.8及以上(1) 安装&#xff1a;默认安装(2) 环境变量配置新建JAVA_HOME:安装路径新建CLASSPath%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar在path中增加&#xff1a;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin&#xff1b;(3) 验证…

猫的眼睛有几种颜色?

在猫咪神秘而迷人的世界里&#xff0c;它们的眼睛犹如璀璨星辰&#xff0c;闪烁着各异的光芒&#xff0c;颜色丰富多样&#xff0c;令人着迷。 猫眼睛的颜色&#xff0c;粗略一数&#xff0c;常见的便有黄色、蓝色、绿色、棕色&#xff0c;还有那神秘的异瞳。这些色彩并非无端生…

PHP框架+gatewayworker实现在线1对1聊天--接收消息(7)

文章目录 接收消息的原理接收消息JavaScript代码 接收消息的原理 接收消息&#xff0c;就是接受服务器转发的客户端消息。并不需要单独创建函数&#xff0c;因为 ws.onmessage会自动接收消息。我们需要在这个函数里进行处理。因为初始化的时候&#xff0c;已经处理的init类型的…

校园周边美食探索及分享平台的设计与实现(源码+数据库+文档)

亲测完美运行带论文&#xff1a;文末获取源码 文章目录 项目简介&#xff08;论文摘要&#xff09;运行视频包含的文件列表&#xff08;含论文&#xff09;前台运行截图后台运行截图 项目简介&#xff08;论文摘要&#xff09; &#xff1a; 美食一直是与人们日常生活息息相关…

基于深度学习的视觉检测小项目(七) 开始组态界面

开始设计和组态画面。 • 关于背景和配色 在组态画面之前&#xff0c;先要确定好画面的风格和色系。如果有前端经验和美术功底&#xff0c;可以建立自己的配色体系。像我这种工科男&#xff0c;就只能从网络上下载一些别人做好的优秀界面&#xff0c;然后在photo shop中抠取色…

wps版excel中如何快速生成倒序序号?

使用wps办公软件打开的excel文件&#xff1a; 效果如下&#xff1a; 方法&#xff1a; 如&#xff1a;想生成此列序号从101~13序号&#xff0c;倒序排列。 在第1个格子中输入开头的最小数字&#xff1a;13 点击一下【13】这个单元格&#xff0c;然后鼠标放在右下角&#xff…

jupyter出现“.ipynb appears to have died. It will restart automatically.”解决方法

原因 解决方法&#xff1a;更新jupyter的版本 1.打开anaconda prompt 2、更新jupyter版本 在anaconda prompt输入以下指令 conda update jupyter如图&#xff1a;

【Flink CDC】Flink CDC的Schema Evolution表结构演变的源码分析和流程图

Flink CDC版本&#xff1a;3.2.1 说明&#xff1a;本文从SchemaOperator接收到&#xff0c;表结构变更事件开始&#xff0c;表结构变更事件应由source端产生&#xff0c;本文不讨论。 可以先看流程图&#xff0c;研究源码。 参考文章&#xff1a; Flink cdc3.0动态变更表结构—…

【编译原理与技术(李文生第二版)】期末复习

第五章 语法制导定义第五章 设计翻译方案√第六章 语义分析-类型表达式&#xff08;仅记录&#xff0c;没说考&#xff09;第七章 参数传递 √第七章 运行栈、display表 √例题1&#xff1a;来源&#xff1a;课件例题2&#xff1a;来源&#xff1a;教材7.4例题3&#xff1a;来源…

SpringBoot环境和Maven配置

SpringBoot环境和Maven配置 1. 环境准备2. Maven2.1 什么是Maven2.2 为什么要学 Maven2.3 创建一个 Maven项目2.4 Maven核心功能2.4.1 项目构建2.4.2 依赖管理2.4.3 Maven Help插件 2.5 Maven 仓库2.5.1本地仓库2.5.2 中央仓库2.5.3 私有服务器, 也称为私服 2.6 Maven设置国内源…

五个不同类型的数据库安装

一、 官方首页下载 打开 MySQL 官方首页&#xff0c;链接为&#xff1a; MySQL 进去社区后选择合适的版本进行安装 安装细节 依图一路next 点击finish结束安装 二、 在线YUM仓库 将该安装包的下载链接在 Linux 操作系统中按照以下命令直接进行下载 三、 二进制本地 通过该链接…

决定系数(R²分数)——评估回归模型性能的一个指标

目录 1.定义 2.计算举例 3. 结果分析 1.定义 R&#xff08;R平方&#xff09;分数&#xff0c;也称为决定系数&#xff0c;是用来评估回归模型性能的一个指标。它表示自变量解释因变量变异性的比例。R分数的取值范围通常在0到1之间&#xff0c;其值越接近1&#xff0c;说明…

基于单片机的直流稳压电源的设计(论文+源码)

1.系统方案设计 在本次直流稳压电源的设计中&#xff0c;其关键指标如下&#xff1a; 系统输入电压220V交流系统输出直流0到12V可调&#xff0c;步进可以达到0.1V电流最大输出可以到2A具有短路保护功能可以通过液晶或者数码管等显示设备显示当前输出电压 2. 电路图

排序算法——堆排序

什么是堆 堆就是一种特殊的二叉树&#xff0c;他有以下特点&#xff1a; 堆中某个节点的值总是不大于或不小于其父节点的值&#xff1b; 堆总是一棵完全二叉树。 堆又可以分为大根堆和小根堆 大根堆&#xff1a;根节点最大&#xff0c;每个节点都小于或等于父节点 小跟堆&am…