广告
返回顶部
首页 > 资讯 > 后端开发 > GO >Golang中怎么对错误进行处理
  • 185
分享到

Golang中怎么对错误进行处理

2024-04-02 19:04:59 185人浏览 独家记忆
摘要

这期内容当中小编将会给大家带来有关golang中怎么对错误进行处理,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。首先介绍几种常见的创建错误的方法基于字符串的错误err1&

这期内容当中小编将会给大家带来有关golang中怎么对错误进行处理,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

首先介绍几种常见的创建错误的方法

基于字符串的错误

err1 := errors.New("math: square root of negative number") err2 := fmt.Errorf("math: square root of negative number %g", x)

带有数据的自定义错误

package serr  import (   "fmt"   "GitHub.com/satori/Go.uuid"   "log"   "runtime/debug"   "time" ) // 自定义基础错误类型 type BaseError struct {   InnerError error   Message    string   StackTrace string   Misc       map[string]interface{} }  func WrapError(err error, message string, messageArgs ...interface{}) BaseError {   return BaseError{     InnerError: err,     Message:    fmt.Sprintf(message, messageArgs),     StackTrace: string(debug.Stack()),     Misc:       make(map[string]interface{}),   } }  func (err *BaseError) Error() string { // 实现 Error 接口   return err.Message }  // 具体使用 // "intermediate" module type IntermediateErr struct {   error }  func runJob(id string) error {   const jobBinPath = "/bad/job/binary"   isExecutable, err := isGloballyExec(jobBinPath)   iferr != nil{     return IntermediateErr{wrapError( err,     "cannot run job %q: requisite binaries not available",     id, )}   } else if isExecutable == false {     return wrapError(       nil,       "cannot run job %q: requisite binaries are not executable", id,     )   }   return exec.Command(jobBinPath, "--id="+id).Run() }

抛出问题

开发中经常需要检查返回的错误值并作相应处理。下面给出一个最简单的示例。

import (    "database/sql"    "fmt" )  func GetSql() error {    return sql.ErrNoRows }  func Call() error {    return GetSql() }  func main() {    err := Call()    if err != nil {       fmt.Printf("got err, %+v\n", err)    } } //Outputs: // got err, sql: no rows in result set

有时需要根据返回的 error 类型作不同处理,例如:

import (    "database/sql"    "fmt" )  func GetSql() error {    return sql.ErrNoRows }  func Call() error {    return GetSql() }  func main() {    err := Call()    if err == sql.ErrNoRows {       fmt.Printf("data not found, %+v\n", err)       return    }    if err != nil {       // Unknown error    } } //Outputs: // data not found, sql: no rows in result set

实践中经常需要为错误增加上下文信息后再返回,以方便调用者了解错误场景。例如 Getcall 方法时常写成:

func Getcall() error {    return fmt.Errorf("GetSql err, %v", sql.ErrNoRows) }

不过这个时候 err==sql.ErrNoRows  就不成立了。除此之外,上述写法都在返回错误时都丢掉了调用栈这个重要的信息。我们需要更灵活、更通用的方式来应对此类问题。

解决方案

针对存在的不足,目前有几种解决方案。这些方式可以对错误进行上下文包装,并携带原始错误信息, 还能尽量保留完整的调用栈

方案 1:github.com/pkg/errors

如果只有错误的文本,我们很难定位到具体的出错地点。虽然通过在代码中搜索错误文本也是有可能找到出错地点的,但是信息有限。所以,在实践中,我们往往会将出错时的调用栈信息也附加上去。调用栈对消费方是没有意义的,从隔离和自治的角度来看,消费方唯一需要关心的就是错误文本和错误类型。调用栈对实现者自身才是是有价值的。所以,如果一个方法需要返回错误,我们一般会使用  errors.WithStack(err) 或者 errors.Wrap(err,"custom message")  的方式,把此刻的调用栈加到error里去,并且在某个统一地方记录日志,方便开发者快速定位问题。

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. Wrap 方法用来包装底层错误,增加上下文文本信息并附加调用栈。一般用于包装对第三方代码(标准库或第三方库)的调用。

  3. WithMessage 方法仅增加上下文文本信息,不附加调用栈。如果确定错误已被 Wrap 过或不关心调用栈,可以使用此方法。注意:不要反复 Wrap  ,会导致调用栈重复

  4. Cause 方法用来判断底层错误 。

现在我们用这三个方法来重写上面的代码:

import (    "database/sql"    "fmt"     "github.com/pkg/errors" )  func GetSql() error {    return errors.Wrap(sql.ErrNoRows, "GetSql failed") }  func Call() error {    return errors.WithMessage(GetSql(), "bar failed") }  func main() {    err := Call()    if errors.Cause(err) == sql.ErrNoRows {       fmt.Printf("data not found, %v\n", err)       fmt.Printf("%+v\n", err)       return    }    if err != nil {       // unknown error    } } 

从输出内容可以看到, 使用 %v 作为格式化参数,那么错误信息会保持一行, 其中依次包含调用栈的上下文文本。使用 %+v  ,则会输出完整的调用栈详情。如果不需要增加额外上下文信息,仅附加调用栈后返回,可以使用 WithStack 方法:

func GetSql() error {    return errors.WithStack(sql.ErrNoRows) }

注意:无论是 Wrap , WithMessage 还是 WithStack ,当传入的 err 参数为 nil 时, 都会返回nil,  这意味着我们在调用此方法之前无需作 nil 判断,保持了代码简洁

方案 2:golang.org/x/xerrors

结合社区反馈,Go 团队开始考虑在 Go 2 中简化错误处理的提案。Go 核心团队成员 Russ Cox 在xerrors中部分实现了提案中的内容。它用与  github.com/pkg/errors 相似的思路解决同一问题, 引入了一个新的 fmt 格式化动词: %w,使用 Is 进行判断。

import (    "database/sql"    "fmt"     "golang.org/x/xerrors" )  func Call() error {    if err := GetSql(); err != nil {       return xerrors.Errorf("bar failed: %w", GetSql())    }    return nil }  func GetSql() error {    return xerrors.Errorf("GetSql failed: %w", sql.ErrNoRows) }  func main() {    err := Call()    if xerrors.Is(err, sql.ErrNoRows) {       fmt.Printf("data not found, %v\n", err)       fmt.Printf("%+v\n", err)       return    }    if err != nil {       // unknown error    } } 

与 github.com/pkg/errors 相比,它有几点不足:

  • 使用 : %w 代替了 Wrap , 看似简化, 但失去了编译期检查。如果没有冒号,或 : %w  不位于于格式化字符串的结尾,或冒号与百分号之间没有空格,包装将失效且不报错;

  • 而且,调用 xerrors.Errorf 之前需要对参数进行nil判断。这完全没有简化开发者的工作

方案 3:Go 1.13 内置支持

Go 1.13 将 xerrors 的部分功能(不是全部)整合进了标准库。它继承了上面提到的 xerrors 的全部缺点,  并额外贡献了一项。因此目前没有使用它的必要。

import (    "database/sql"    "errors"    "fmt" )  func Call() error {    if err := GetSql(); err != nil {       return fmt.Errorf("Call failed: %w", GetSql())    }    return nil }  func GetSql() error {    return fmt.Errorf("GetSql failed: %w", sql.ErrNoRows) }  func main() {    err := Call()    if errors.Is(err, sql.ErrNoRows) {       fmt.Printf("data not found,  %+v\n", err)       return    }    if err != nil {       // unknown error    } } 

上面的代码与 xerrors 版本非常接近。但是它不支持调用栈信息输出, 根据官方的说法, 此功能没有明确的支持时间。因此其实用性远低于  github.com/pkg/errors。

Golang 中将来可能的错误处理方式

在 Go2 的草案中,我们看到了有关于 error 相关的一些提案,那就是 check/handle 函数。

我们也许在下一个大版本的 Golang 可以像下面这样处理错误:

import "fmt" func game() error {     handle err {         return fmt.Errorf("dependencies error: %v", err)     }      resource := check findResource() // return resource, error     defer func() {         resource.Release()     }()      profile := check loadProfile() // return profile, error     defer func() {         profile.Close()     }      // ... }

感兴趣的同学可以关注下这个提案:https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md

得出结论

  • 重要的是要记住,包装错误会使该错误成为 api 的一部分。如果您不想将来将错误作为 API  的一部分来支持,则不应包装该错误。无论是否包装错误,错误文本都将相同。那些试图理解错误的人将得到相同的信息,无论采用哪种方式;  是否要包装错误的选择取决于是否要给程序提供更多信息,以便他们可以做出更明智的决策,还是保留该信息以保留抽象层。

通过以上对比, 相信你已经有了选择。再明确一下我的看法,如果你正在使用 github.com/pkg/errors  ,那就保持现状吧。目前还没有比它更好的选择。如果你已经大量使用 golang.org/x/xerrors , 别盲目换成 go 1.13 的内置方案。

总的来说,Go 在诞生之初就在各个方面表现得相当成熟、稳健。在演进路线上很少出现犹疑和摇摆, 而在错误处理方面却是个例外。除了被广泛吐槽的 if err  != nil 之外, 就连其改进路线也备受争议、分歧明显,以致于一个改进提案都会因为压倒性的反对意见而不得不作出调整。好在 Go  团队比以前更加乐于倾听社区意见,团队甚至专门就此问题建了个反馈收集页面。

上述就是小编为大家分享的Golang中怎么对错误进行处理了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注编程网GO频道。

您可能感兴趣的文档:

--结束END--

本文标题: Golang中怎么对错误进行处理

本文链接: https://www.lsjlt.com/news/74108.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Golang中怎么对错误进行处理
    这期内容当中小编将会给大家带来有关Golang中怎么对错误进行处理,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。首先介绍几种常见的创建错误的方法基于字符串的错误err1&...
    99+
    2022-10-19
  • Nodejs中怎么对错误进行处理
    今天就跟大家聊聊有关Nodejs中怎么对错误进行处理,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。假设我们有以下代码const net&n...
    99+
    2022-10-19
  • golang如何进行错误处理
    这篇“golang如何进行错误处理”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“golang如何进行错误处理”文章吧。Gol...
    99+
    2023-07-04
  • Golang中怎么优雅地处理错误
    本文小编为大家详细介绍“Golang中怎么优雅地处理错误”,内容详细,步骤清晰,细节处理妥当,希望这篇“Golang中怎么优雅地处理错误”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。一、错误分类在 Golang ...
    99+
    2023-07-05
  • go goroutine 怎样进行错误处理
    目录前言 通过错误日志记录 利用 channel 传输 使用 sync/errgroup 总结 前言 在 Go 语言程序开发中,goroutine 的使用是比较频繁的,因此在日常编...
    99+
    2022-11-12
  • vbScript中如何进行错误处理
    这篇文章将为大家详细讲解有关vbScript中如何进行错误处理,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。vbscript中,错误处理使用on error resume next来完成,如果在你的代码里...
    99+
    2023-06-08
  • Golang开发建议:如何进行有效的错误处理
    Golang作为一种现代化的编程语言,以其高效、简洁、安全等特点受到了广泛的关注和使用。错误处理是任何程序开发中都无法回避的部分,而Golang又提供了一套强大的错误处理机制。本文将介绍如何在Golang中进行有效的错误处理,以帮助开发者编...
    99+
    2023-11-22
    错误处理 (Error handling) Golang开发 (Golang development) 有效的 (eff
  • thinkphp5中怎么进行错误处理的相关信息
    本篇内容介绍了“thinkphp5中怎么进行错误处理的相关信息”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!错误处理机制ThinkPHP5提...
    99+
    2023-07-05
  • golang 语言中错误处理机制
    与其他主流语言如 Javascript、Java 和 Python 相比,Golang 的错误处理方式可能和这些你熟悉的语言有所不同。所以才有了这个想法根大家聊一聊 golang 的...
    99+
    2022-11-12
  • PHP中PDO如何进行错误处理
    这篇文章给大家分享的是有关PHP中PDO如何进行错误处理的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。在之前的学习中我们已经学会出来了通过PDO获取查询结果,那接下来就要学习一下PDO的错误处理, 在 PDO 中...
    99+
    2023-06-25
  • Golang中的错误处理深入分析
    目录一、Go的内建类型error二、怎么判断一个错误值具体代表那一类错误知道错误类型的所属范围知道错误变量是哪几个值三、错误值体系的两种方法立体的-错误类型体系扁平的-错误值列表一、...
    99+
    2023-01-09
    Go错误处理 GoLang错误处理
  • golang为什么要统一错误处理
    目录1.为什么要统一错误处理2.后端封装统一接口3.核心函数4.常见错误处理5.共用错误处理6.解析错误原因1.为什么要统一错误处理 统一错误处理的目的是为了前端开发接收到后端的st...
    99+
    2022-11-13
  • Node.js中怎么对CORS进行处理
    今天就跟大家聊聊有关Node.js中怎么对CORS进行处理,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。什么是CORSCORS 是“跨域资源共享”的...
    99+
    2022-10-19
  • Android中怎么对cookie进行处理
    本篇文章给大家分享的是有关Android中怎么对cookie进行处理,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。android 客户端 Cookie处理Cookie,有时也用...
    99+
    2023-05-30
    android cookie
  • c++运行时错误怎么处理
    处理 C++ 运行时错误的一般方法包括:1. 异常处理:使用 try-catch 块来捕获可能抛出的异常,并在 catch 块中处理...
    99+
    2023-10-08
    c++
  • JavaScript中怎么处理错误
    这篇文章主要为大家展示了“JavaScript中怎么处理错误”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“JavaScript中怎么处理错误”这篇文章吧。Dem...
    99+
    2022-10-19
  • 使用Raygun对Node.js应用进行错误处理的方法
    用我们的 raygun4node 包,能提供一种把您的Node.js错误发送给Raygun的便利办法. 它可以很容仪的使用 npm 安装: npm install raygun 其能给您提供一...
    99+
    2022-06-04
    错误 方法 Raygun
  • Golang中的错误处理方式有哪些
    这篇文章主要讲解了“Golang中的错误处理方式有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang中的错误处理方式有哪些”吧!错误类型在Golang中,错误类型是错误处理的基本...
    99+
    2023-07-06
  • Golang中的错误处理的示例详解
    目录1、panic2、包装错误3、错误类型判断4、错误值判断1、panic 当我们执行panic的时候会结束下面的流程: package main import "fmt" fu...
    99+
    2022-11-11
  • Nginx中怎么对图片进行处理
    本篇文章给大家分享的是有关Nginx中怎么对图片进行处理,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Nginx图片处理一个网管员必备的数据处...
    99+
    2022-10-19
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作