首页 > 其他分享 >go语言处理错误的正确姿势

go语言处理错误的正确姿势

时间:2023-11-07 12:44:05浏览次数:29  
标签:姿势 错误 err Go error go panic 处理错误 函数

Go语言处理错误的正确姿势

原创 枫潇潇兮 程序员技术成长之路 2023-09-20 21:34 发表于福建 收录于合集#go语言58个

在Go语言中,错误处理是通过内置的error类型来实现的,而异常则是通过panicrecover函数来处理。

Error

error是一个内置的接口类型,它的定义如下:

type error interface {    Error() string}

这是一个简单的接口,只要你的类型实现了Error方法(这个方法会返回一个字符串),那么它就实现了error接口。在函数中,如果出现了错误情况,通常会返回一个实现了error接口的值。

Go语言的标准库中已经提供了几个实现了error接口的结构,例如errors.New函数返回的*errors.errorString类型,以及fmt.Errorf函数返回的*errors.errorString类型。

你也可以定义自己的错误类型,只要这个类型实现了error接口就可以。

type MyError struct {  Message string  Err     error}
func (e *MyError) Error() string { return e.Message}

Exception

Go语言没有类似Java或者Python那样的异常机制,但是它提供了panic和recover两个函数,可以在遇到无法恢复的错误状态的时候,终止函数执行。简单来说,panic用于产生异常,而recover用于捕获异常。

panic函数接受一个实现了error接口的对象,或者是一个interface{}类型的对象。调用panic函数会立即停止函数的执行,并且运行defer语句。

recover函数用于捕获由panic函数引起的异常。recover函数只能在defer语句中使用。在正常执行过程中,调用recover会返回nil并且没有其他效果;但是如果当前的goroutine在恐慌中(已经调用过panic函数),调用recover可以捕获到panic的输入值,并且恢复正常的执行。

func main() {    defer func() {        if err := recover(); err != nil {            fmt.Println("Recovered from", err)        }    }()    panic("A severe error occurred: stopping the program!")}

在上面的例子中,当panic函数被调用(可能是由于一些严重的错误导致的)时,执行会立即停止,然后执行defer函数。在defer函数里面,我们调用了recover函数,捕获到了panic的输入值,之后函数就可以正常的执行下去了。

如何优雅的处理错误

    Go语言鼓励开发人员对每个错误进行明确的处理。这是Go语言对异常处理的设计哲学,目标是在函数签名上让潜在的错误变得明显。这种方式鼓励开发者更早更显眼的注意到错误处理,而不是像某些语言那样抛出异常然后在别的地方处理。

    优雅处理Error的一些方法包括:

  • 使用errors包中的函数产生简单的纯错误文本信息。

  • 使用fmt.Errorf生成错误信息,并包含有用的变量值。

  • 创建自定义错误类型,可以包含更多信息,比如错误的上下文,使得错误更具有信息价值。

    在Go中,错误被视为一等公民,并且Go鼓励你明确处理每一个可能的错误。虽然这可能会让代码看起来有些繁琐,但是这也会让你的应用更加稳健,因为你很难忽略处理错误。

 

一、定义返回错误

func LowerLevelFunction() (string, error) {    // 执行一些操作    return result, err}
func HigherLevelFunction() { result, err := LowerLevelFunction() if err != nil { // 处理错误 } else { // 使用结果 }}

实际上,Go语言中的错误处理就是这样简单直接。你需要在你的函数中返回一个错误,并在接收到错误时处理它。几乎所有的 return 语句都包含了一个错误值,这就是 Go 语言让错误处理显而易见的方式。

二、封装错误继续抛

_, err := os.Open("non-existing-file")if err != nil {    return fmt.Errorf("failed to open file: %w", err)}

上述代码中的%w标志符在Go 1.13版本被引入,它允许将原始错误包装在新的错误中。

你也可以创建自定义错误类型,提供更多上下文信息。例如:

type customError struct {  originalError error  contextInfo   string}
func (ce customError) Error() string { return fmt.Sprintf("failed: %s: %v", ce.contextInfo, ce.originalError)}
_, err := os.Open("non-existing-file")if err != nil { return customError{ originalError: err, contextInfo: "failed to open file", }}

在这个例子中,customError包括了原始的错误和额外的上下文信息。并且,customError实现了Error()方法,使其满足error接口。

总的来说,包装错误并向上抛出可以帮助我们提供更多的错误上下文,以便于更好地排查问题。在Go 1.13及以上的版本,我们还可以使用errors.Iserrors.As去检查和获取原始的错误。

errors.Is函数用于检测一个错误是否与特定的错误相同。它会考虑错误的原始类型和通过fmt.Errorf包装的错误。

_, err := os.Open("non-existing-file")if errors.Is(err, os.ErrNotExist) {    fmt.Println("file does not exist")} else {    fmt.Println("other error")}

以上的代码,如果打开文件的错误是因为文件不存在(os.ErrNotExist),则返回文件不存在的错误信息,否则返回其他错误。

errors.As函数用于将错误转为特定的错误类型,如果转换失败,将返回 false。

_, err := os.Open("non-existing-file")if pathError, ok := err.(*os.PathError); ok {    fmt.Println("failed at path:", pathError.Path)} else {    fmt.Println("other error")}

以上的代码,如果打开文件的错误是*os.PathError类型的错误,则获取失败的文件路径。如果不是这种类型的错误,则返回其他错误。

 

收录于合集 #go语言  58个 上一篇Go如何实现分布式锁下一篇Go语言实现时间窗口限流器 个人观点,仅供参考 阅读 429 程序员技术成长之路 ​ 喜欢此内容的人还喜欢   PHP如何处理分库分表     我看过的号 程序员技术成长之路 不看的原因   Go语言二叉树实现不再难!详解核心技巧!     我看过的号 Go先锋 不看的原因   Golang Map底层实现简述     孟斯特 不看的原因   关注公众号后可以给作者发消息             继续访问取消        

人划线

 

标签:姿势,错误,err,Go,error,go,panic,处理错误,函数
From: https://www.cnblogs.com/cheyunhua/p/17814752.html

相关文章

  • Gene Ontology (GO)简介
        为了查找某个研究领域的相关信息,生物学家往往要花费大量的时间,更糟糕的是,不同的生物学数据库可能会使用不同的术语,好比是一些方言一样,这让信息查找更加麻烦,尤其是使得机器查找无章可循。GeneOntology就是为了解决这种问题而发起的一个项目。    GeneOntology中最基......
  • Django实战项目-学习任务系统-发送短信通知
    接着上期代码内容,继续完善优化系统功能。本次增加发送短信通知功能,学习任务系统发布的任务,为了更加及时通知到学生用户,再原有发送邮件通知基础上,再加上手机短信通知功能。第一步:开通短信通知服务目前短信通知都是要收费的,本人还没发现免费的短信通知服务,如有网友知道免费资源请......
  • Gene Ontology (GO) 简介
    为了查找某个研究领域的相关信息,生物学家往往要花费大量的时间,更糟糕的是,不同的生物学数据库可能会使用不同的术语,好比是一些方言一样,这让信息查找更加麻烦,尤其是使得机器查找无章可循。GeneOntology就是为了解决这种问题而发起的一个项目。GeneOntology中最基本的概念是term。GO......
  • django的paginator都是假分页,数据量大很卡
    paginator使用defget(self,request,*args,**kwargs):rs_data={'count':0,'items':[]}page=int(self.request.GET.get('page',1))page_size=int(self.request......
  • Django动态创建表模型,并使用drf
    序列化器fromrest_frameworkimportserializersclassMySerializer(serializers.ModelSerializer):"""序列化器"""classMeta:model=None#可以设置为None,动态生成之后,再通过反射来重新设置。fields='__all__'......
  • Golang实现简单的后门程序
    packagemainimport( "io" "net" "os/exec")funcmain(){ var( listenernet.Listener errerror connnet.Conn ) listener,err=net.Listen("tcp",":8080") iferr!=nil{ panic(e......
  • Go 接口-契约介绍
    Go接口-契约介绍目录Go接口-契约介绍一、接口基本介绍1.1接口类型介绍1.2为什么要使用接口1.3面向接口编程1.4接口的定义二、空接口2.1空接口的定义2.2空接口的应用2.2.1空接口作为函数的参数2.2.2空接口作为map的值2.3接口类型变量2.4类型断言三、尽量定义“小接口......
  • Django查询之—— Q查询
    Q查询 作用:filter的字段筛选条件指定多个,默认是and连接.要实现or或者not需要借助Q查询首先要导入模块fromdjango.db.modelsimportQQ(字段__条件=值) 连接条件:andornot#and的3种情况1.filter中指定多个参数逗号隔开:filter(参数1,参数2)......
  • Django查询之—— F查询
    F查询 作用:能够帮助你直接获取到表中某个字段对应的数据首先要导入模块fromdjango.db.modelsimportF 用法一:查询卖出数大于库存数的书籍res=models.Book.objects.filter(sale__gt=F('stock'))print(res)用法二:将所有书籍的价格提升500块res=mode......
  • django+爬虫+钉钉机器人
    Views类urls类Html结果......