Golang实践之Error创建和处理详解

 更新时间:2023年09月11日 10:18:48   作者:小雄Ya  
在 C#、Java 等语言中常常使用 try...catch的方式来捕获异常,但是在Golang 对于错误处理有不同的方式,像网上也有很多对 error 处理的最佳实践的文章,其中很多其实就是对 error 的统一封装,使用规范进行约束,本文主要是记录自己对处理 Error 的一些认识和学习

error 基本概念

type error interface{
    Error() string
}

Golang 中 error类型是一个具有单个方法的接口,其内置方法是返回描述错误的字符串。Go 语言创始人觉得异常机制会导致控制流程混乱,降低代码的可读性,所以期望异常是一种可预知的。所以在使用时应当适当的返回 error ,然后调用方就可以更明确知道错误,进而再处理异常。同样也说明了开发人员在 coding 时要能识别和预测可能发生错误,再进行处理,而不是忽略错误,

panic 和 recover

但可能也会出现一些我们无法预料的错误情况。比较严重的程序错误导致发生 panic 就会使程序结束,所以它又提供一个 recover 来捕获 panic ,以便发生panic时能够重新执行启动程序。

defer func() {
        if r := recover(); r != nil {
            fmt.Println("重新启动程序:", r)
        }
}()

recover 函数最好在主函数中且必须在 defer 语句总使用,为了保证发生 panic 时被调用,如果没有panic时recover 函数将会返回 nil。

对于panic 的错误,应当全面记录错误信息,这样才有利于排查问题。对于一些比较重要的服务应当适当增加报警机制以通知相关团队或人员。

创建错误

// 方式1:使用 fmt.Errorof("")
func div(x, y int)(int,error){
    if y==0 {
        return 0,fmt.Errorof("除数 %d 不能为0",y)
    }
    return x/y, nil
}
// 方式2: 使用errors.New("")
ErrDivByZero := errors.New("除数不能为0")
return 0,ErrDivByZero
// 方式3:使用 errors.Wrap(err, "除数不能为0")
return 0,errors.Wrap(err, "除数不能为0")

方式1中 fmt.Errorf 函数允许使用格式化字符串创建新错误。

errors.Wrap 函数允许使用上下文包装error,使用场景:当函数调用另一个方法时遇到的错误而导致无法完成业务流程,那可能需要从函数返回错误。使用 errors.Wrap 函数需要注意:因其除了错误信息外还附加了堆栈信息,所以不能在程序中大量使用。

以上3种可以很简单方便的创建错误。当然支持自定义错误类型,通过创建实现 error 接口的新类型。例如:

// 方式4: 自定义错误类型
type MathCalError struct {
    message string
}
// 实现 Error 方法
func (e *MathCalError) Error() string {
    return e.message
}
func div(x, y int) (int, error) {
    if y == 0 {
        return 0, &MathCalError{"除数不能为 0"}
    }
    return x / y, nil
}

处理错误

根据遇到到场景,基本对于错误的处理大致有下面五种情况:

  • 忽略错误:调用方对于发生错误觉得没有任何影响,那么可以不接收直接忽略
  • 记录错误并继续执行:调用方觉得错误无影响但需要进行记录,可以接受记录
  • 传递错误:继续传递错误。
  • 错误重试:某功能错误需要再重试,如请求第三方接口超时时想再重试。设置重试次数限制,以防止错误持续存在时出现无限循环。
  • 严重错误终止程序:若有些错误期望终止程序,那直接 panic 处理。
// 忽略错误
result,_ := getUser()
// 记录错误
result,err := getUser();err!=nil{
    log,writerInfo("something error", err.Error())
}
// 传递错误
result,err := getUser();err!=nil{
   return err
}
// 错误重试
retryCount := 0
 maxRetryCount := 3
for {
    result,err := getUser();
    if err!=nil{
       return err
       if retryCount >= maxRetryCount{
           return err
       } 
    }
    select {
    case <-ctx.Done():
     return ctx.Err()
    case <-time.After(time.Duration(retryCount) * time.Second):
     retryCount++
     continue
 }
}
//错误后直接 panic
if err := getUser(); err != nil {
    panic("something wrong") 
}

项目中使用 Error 的方案

方案一 :定义 ErrorMessage 包

项目中可以定义一个含有所有错误信息的包,然后在使用时直接引用。

package errorMsg
import "errors"
var UndefinedError = errors.New("未定义")
var InvalidateParamsError = errors.New("不合法参数")
// main 函数中使用
func getUser() error {
    return errorMsg.UndefinedError
}

方案二:自定义 error 类型

type ParamNotFound NotFound
type ValueNotFound NotFound
type NotFound struct {
	msg string
}
func (n *NotFound) Error() string {
	return n.msg
}
// 通过使用 switch 处理不同类型的错误,
func handleErrors(err error) {
  switch v := err.(type) {
  case ParamNotFound:
    fmt.Printf("ParamNotFound: %v\n", v)
  case ValueNotFound:
    fmt.Printf("ValueNotFound: %v\n", v)
  default:
    fmt.Printf("Other error: %v\n", v)
  }
}

最后

有效的错误处理对于构建可靠的服务至关重要,个人觉得最佳的实践是团队内部的统一规范。没有最佳实践和方案,只有最适合的你的场景的实践。

以上就是Golang实践之Error创建和处理详解的详细内容,更多关于Golang Error创建和处理的资料请关注脚本之家其它相关文章!

相关文章

  • Go语言实现定时器的方法

    Go语言实现定时器的方法

    这篇文章主要介绍了Go语言实现定时器的方法,涉及Go语言时间操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02
  • 关于Go你不得不知道的一些实用小技巧

    关于Go你不得不知道的一些实用小技巧

    开发语言上Go成为高并发业务开发的主流语言,再加上云原生技术底座的驱动,Go语言风光无限,下面这篇文章主要给大家介绍了关于Go你不得不知道的一些实用小技巧,需要的朋友可以参考下
    2022-11-11
  • Golang文件读写操作详情

    Golang文件读写操作详情

    这篇文章主要介绍了Golang文件读写操作详情,文件是数据源(保存数据的地方)的一种,文件最主要的作用就是保存数据,文件在程序中是以流的形式来操作的,更多详细内容需要的朋友可以参考一下
    2022-07-07
  • 关于golang中平行赋值浅析

    关于golang中平行赋值浅析

    这篇文章主要给大家介绍了关于golang中平行赋值的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用golang具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-08-08
  • Golang配置管理库 Viper的教程详解

    Golang配置管理库 Viper的教程详解

    这篇文章主要介绍了Golang 配置管理库 Viper,使用 viper 能够很好的去管理你的配置文件信息,比如数据库的账号密码,服务器监听的端口,你可以通过更改配置文件去更改这些内容,而不用定位到那一段代码上去,提高了开发效率,需要的朋友可以参考下
    2022-05-05
  • gtoken替换jwt实现sso登录的问题小结

    gtoken替换jwt实现sso登录的问题小结

    这篇文章主要介绍了gtoken替换jwt实现sso登录,主要介绍了替换jwt的原因分析及gtoken的优势,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • Go 自定义package包设置与导入操作

    Go 自定义package包设置与导入操作

    这篇文章主要介绍了Go 自定义package包设置与导入操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • Go使用Viper库读取YAML配置文件的示例代码

    Go使用Viper库读取YAML配置文件的示例代码

    Viper是适用于Go应用程序的完整配置解决方案,它被设计用于在应用程序中工作,并且可以处理所有类型的配置需求和格式,本文给大家介绍了Go使用Viper库读取YAML配置文件的方法,需要的朋友可以参考下
    2024-05-05
  • Go Excelize API源码解读GetSheetViewOptions与SetPageLayout

    Go Excelize API源码解读GetSheetViewOptions与SetPageLayo

    这篇文章主要为大家介绍了Go Excelize API源码解读GetSheetViewOptions与SetPageLayout方法示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • Golang中int类型和字符串类型相互转换的实现方法

    Golang中int类型和字符串类型相互转换的实现方法

    在日常开发中,经常需要将数字转换为字符串或者将字符串转换为数字,在 Golang 中,有一些很简便的方法可以实现这个功能,接下来就详细讲解一下如何实现 int 类型和字符串类型之间的互相转换,需要的朋友可以参考下
    2023-09-09

最新评论