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的原型模式,感兴趣的通过跟着小编一起来看看吧
    2023-07-07
  • 一文详解go闭包(Closure)使用教程

    一文详解go闭包(Closure)使用教程

    在Go语言中,闭包(Closure)是一种特殊的函数,它可以捕获其创建时所在作用域中的变量,本文给大家详细介绍了go闭包(Closure)使用教程,感兴趣的朋友可以参考下
    2024-01-01
  • Golang中SSE协议实现方法

    Golang中SSE协议实现方法

    Gin框架通过Server-SentEvents(SSE)实现流式返回,关键步骤包括设置正确的响应头、使用Flusher确保数据立即发送、处理客户端中断和错误,本文给大家介绍Golang中SSE协议实现方法,感兴趣的朋友跟随小编一起看看吧
    2026-01-01
  • go语言中的指针自动解引用

    go语言中的指针自动解引用

    Go语言中,编译器会自动解引用指针来访问字段,自动解引用使得使用指针访问结构体字段和方法变得更加直观,降低了编程错误的风险,并使代码更易于理解和维护
    2024-10-10
  • golang实现ping命令的完整代码

    golang实现ping命令的完整代码

    这篇文章给大家介绍了如何使用golang实现ping命令,文中给大家介绍了完整的实现代码,并有详细的图文讲解,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-02-02
  • Go语言开发发送Get和Post请求的示例

    Go语言开发发送Get和Post请求的示例

    这篇文章主要介绍了Go语言开发发送Get和Post请求的示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • go colly 爬虫实现示例

    go colly 爬虫实现示例

    这篇文章主要为大家介绍了go colly 爬虫实现示例,效果是根据输入的浏览器cookie及excel必要行列号,从excel中读取公司名称,查询公司法人及电话号码。并写回到excel中指定行
    2022-09-09
  • golang中之strconv包的具体使用方法

    golang中之strconv包的具体使用方法

    这篇文章主要介绍了golang中之strconv包的具体使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • Go语言中一定要知道的切片使用注意事项总结

    Go语言中一定要知道的切片使用注意事项总结

    了解和掌握切片的使用注意事项,可以避免意外的程序行为,所以本文就来和大家深入探讨一下Go语言切片常见的注意事项,希望对大家有所帮助
    2023-06-06
  • golang简单位运算示例

    golang简单位运算示例

    这篇文章主要介绍了golang简单位运算,包括位移运算、取反及位与位或等运算,需要的朋友可以参考下
    2016-07-07

最新评论