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

13 Go的错误处理

概述

        在上一节的内容中,我们介绍了Go的接口,包括:定义接口、实现接口、使用接口、空接口等。在本节中,我们将介绍Go的错误处理。在Go语言中,错误处理是一种重要的编程模式,它用于处理可能出现的错误或异常情况。Go语言采用了一种简洁而直接的错误处理方式,通过使用内置的error类型和约定的返回值,开发人员可以有效地处理和传递错误信息。

errors包

        Go语言中的errors包主要用于进行错误处理,它提供了一些简单的接口和函数,用于创建和操作错误值。下面,我们介绍errors包中一些常见函数的使用方法。

        创建错误:可以使用errors.New()函数来创建一个简单的错误值。它接受一个字符串参数,用于表示错误信息。比如:

          err := errors.New("something is wrong")

        包装错误:可以使用errors.Wrap()函数来包装一个错误值。它接受一个错误值和一个字符串参数,返回一个新的错误值,其中包含了原始错误的详细信息。比如:

          err := errors.Wrap(originalError, "something is wrong")

        获取错误信息:可以使用errors.Unwrap()函数来获取包装错误中的原始错误。它接受一个错误值,返回原始错误。比如:

          originalErr := errors.Unwrap(err)

        判断错误类型:可以使用errors.Is()函数来判断一个错误是否属于特定的类型。它接受一个错误值和一个类型参数,返回一个布尔值表示是否匹配。比如:

          if errors.Is(err, io.EOF)

        错误格式化:可以使用errors.Errorf()函数来创建一个格式化的错误值。它接受一个格式化字符串和变量参数,类似于fmt.Sprintf()函数。比如:

          err := errors.Errorf("something is wrong: %s", errorMessage)

返回错误

        在Go语言中,通常将函数的最后一个返回值定义为error类型,用于指示函数执行过程中是否发生了错误。如果函数执行成功,该错误值为nil;如果函数执行失败,则将相应的错误值赋给错误变量。这种约定使得函数的调用者可以轻松地检查函数是否返回了错误,并根据需要采取相应的处理措施。

        在下面的示例代码中,divide函数接受两个float64类型的参数,并返回一个float64类型的结果和一个error类型的错误。当除数为零时,函数会返回一个非零的错误值,用于描述错误信息。在main函数中,我们通过检查错误变量err是否为nil来判断函数是否执行成功。如果err不为nil,则表示函数执行失败,并打印相应的错误信息;否则,打印函数执行的结果。

package main

import "fmt"
import "errors"
  
func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("divisor cannot be zero")
    }

    return a / b, nil
}

func main() {
    result, err := divide(10, 2)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        // 输出:Result: 5
        fmt.Println("Result:", result)
    }

    result, err = divide(10, 0)
    if err != nil {
        // 输出:Error: divisor cannot be zero
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Result:", result)
    }
}

        除了直接返回错误值外,还可以使用多返回值的方式在函数内部进行错误处理。在下面的示例代码中,我们使用一个额外的变量来指示函数是否执行成功。

package main  
  
import "fmt"
import "errors"
  
func divide(a, b float64) (float64, bool, error) {
    if b == 0 {
        return 0, false, errors.New("divisor cannot be zero")
    }

    if b == 1 {
        return 0, false, nil
    }

    return a / b, true, nil
}  
  
func main() {
    result, success, err := divide(10, 1)
    if err != nil {
        fmt.Println("Error:", err)
    } else if !success {
        // 输出:divisor cannot be 1
        fmt.Println("divisor cannot be 1")
    } else {
        fmt.Println("Result:", result)
    }
}

抛出异常

        在Go语言中,抛出异常可以使用panic函数。panic函数是一个内置函数,用于表示发生了一个无法恢复的错误。当panic函数被调用时,当前函数的执行会立即停止,并且向上递归调用栈,直到找到适当的defer语句或函数返回。

        panic函数通常用于处理无法处理的错误情况,比如:内存溢出、空指针引用等。当panic函数被调用时,它会传递一个字符串作为参数,表示发生错误的原因,这个字符串可以被捕获并用于错误处理或日志记录。

        在下面的示例代码中,我们用panic函数抛出了异常。在执行panic函数之前,会打印输出字符串“before panic”。在执行panic函数之后,main函数的执行会立即停止,故不会继续执行后面的打印语句。

package main

import "fmt"

func main() {
    // 输出:before panic
    fmt.Println("before panic")

    // 抛出异常
    panic("an exception occured")

    // 以下语句不会被执行
    fmt.Println("after panic")
}

捕获异常

        在Go语言中,捕获异常可以使用recover函数和defer关键字。

        recover函数是一个内建函数,用于从一个panic异常中恢复并继续执行程序。当程序遇到panic时,它会中断当前的执行流程并开始向上层调用栈传播panic,直到被捕获或程序终止。recover函数允许在defer关键字修饰的函数中捕获并处理panic异常,以便程序可以继续执行而不会终止。

        defer关键字用于延迟执行一个函数调用,直到包含它的函数返回之前执行。被defer修饰的函数调用会被推入一个栈中,等到包含它的函数返回时,该函数调用才会被从栈中弹出并执行。defer关键字通常用于在函数返回之前执行一些清理操作,比如:关闭文件、释放资源、打印日志等。它可以用于确保在函数执行结束时,相关的资源被正确释放,避免资源泄漏问题。

        注意:recover函数只能在defer函数中使用,不能在其他上下文中使用。当在defer函数中调用recover时,它会停止panic传播并返回panic的值(如果有的话)。如果没有panic发生,recover函数会返回nil。

        在下面的示例代码中,我们使用defer关键字和匿名函数来创建一个defer函数。在defer函数中,我们调用recover函数来捕获panic异常。如果有panic发生,我们会打印出相应的错误信息。

package main

import "fmt"

func main() {
    defer func() {
        if r := recover(); r != nil {
            // 捕获到异常,输出:an exception caught: an exception occured
            fmt.Println("an exception caught:", r)
        }
    }()

    // 输出:before panic
    fmt.Println("before panic")

    // 抛出异常
    panic("an exception occured")

    // 以下语句不会被执行
    fmt.Println("after panic")
}


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

相关文章:

  • 网络爬虫 Python 第二课
  • k-近邻算法(K-Nearest Neighbors, KNN)详解:机器学习中的经典算法
  • 数据库基本概念学习笔记
  • leetcode-44-通配符匹配
  • 【学习笔记】大模型调优(llms_tuning)
  • 一体化运维监控管理平台:产品架构与功能解析
  • Spark作业串行与并行提交job
  • 6、传统CV之均值滤波
  • 龙芯 操作系统选择和安装
  • 『 MySQL数据库 』数据库之表的约束
  • 基于SSM的校园闲置物品交易平台
  • Docker - 网络
  • ESP32网络开发实例-非接触式水位监测
  • chrome 浏览器个别字体模糊不清
  • 【技术追踪】SAM(Segment Anything Model)代码解析与结构绘制之Mask Decoder
  • 《LeetCode力扣练习》代码随想录——链表(删除链表的倒数第N个节点---Java)
  • elasticsearch 安装
  • 编程怎么学习视频教程,编程实例入门教程,中文编程开发语言工具下载
  • Java中 ==、equals() 、equalsIgnoreCase() 和compareTo() 方法对比详解
  • python中的NumPy和Pandas往往都是同时使用,NumPy和Pandas的在数据分析中的联合使用
  • 基于SSM+Vue的校园共享单车管理系统
  • 【UE5】物体沿样条线移动
  • OSS服务和MinIO存储做一个区分解析
  • 车载开发岗位如何?Android程序员是否转行
  • 对话芯动科技 | 助力云游戏 4K级服务器显卡的探索与创新
  • canal1.1.7实战