如何在Go中向错误中添加额外的信息

news/2025/3/16 23:28:33/

引言

当Go中的函数失败时,该函数将使用error接口返回一个值,以允许调用者处理该失败。在许多情况下,开发人员将使用fmt包中的fmt.Errorf函数来返回这些值。不过,在Go 1.13之前,使用此函数的一个缺点是,您将丢失有关可能导致错误返回的任何错误的信息。为了解决这个问题,开发人员要么使用包来提供一种方法将错误“包装”在其他错误中,要么通过在他们的struct错误类型上实现Error() string方法来创建自定义错误。然而,如果您有许多不需要由调用者显式处理的错误,有时创建这些struct类型可能会很繁琐,因此在Go 1.13中,语言添加了一些功能来更容易处理这些情况。

其中一个功能是能够使用带有error值的fmt.Errorf函数包装错误,该函数稍后可以展开以访问包装后的错误。这将错误包装功能构建到Go标准库中,因此不再需要使用第三方库。

此外,函数errors.Iserrors.As使确定特定错误是否包装在给定错误中的任何位置更容易,还将使您直接访问特定错误,而无需自己拆封所有错误。

在本教程中,你将创建一个程序,使用这些函数在函数返回的错误中包含额外的信息,然后创建你自己的自定义错误struct,以支持包装和解包装功能。

Go中的返回和处理错误

当程序中发生错误时,最好的做法是处理这些错误,让用户永远不会看到它们——但要处理这些错误,你需要首先了解它们。在Go中,你可以通过使用特殊的interface类型(即error接口)从函数中返回有关错误的信息来处理程序中的错误。使用error接口允许任何Go类型作为error值返回,只要该类型定义了Error() string方法。Go标准库提供了为这些返回值创建error的功能,例如fmt.Errorf函数。

在本节中,你将创建一个带有函数的程序,该函数使用fmt.Errorf来返回一个错误,你还将添加一个错误处理程序来检查函数可能返回的错误。如果您想了解有关Go中处理错误的更多信息,请参阅教程,Go中处理错误

许多开发人员都有一个目录来保存当前项目。在本教程中,你将使用一个名为projects的目录。

首先,创建projects目录并导航到它:

mkdir projects
cd projects

projects目录中,创建一个新的errtutorial目录来保存新程序:

mkdir errtutorial

接下来,使用cd命令切换到新目录:

cd errtutorial

进入errtutorial目录后,使用go mod init命令创建一个名为==errtutorial==的新模块:

go mod init errtutorial

创建Go模块后,使用nano或你喜欢的编辑器在errtutorial目录中打开一个名为main.go的文件:

nano main.go

接下来,你将编写一个程序。程序将循环遍历数字13,并使用名为validateValue的函数尝试确定这些数字是否有效。如果数字被确定为无效,程序将使用fmt.Errorf函数生成一个error值并从函数返回。fmt.Errorf函数允许你创建一个error值,其中的错误消息就是你提供给函数的消息。它的工作原理类似于fmt.Printf,但它不是将消息打印到屏幕上,而是将其作为error返回。

然后,在main函数中,将检查错误值是否为nil。如果是nil值,则函数成功并打印valid!消息。如果不是,则打印接收到的错误。

要开始你的程序,将以下代码添加到main.go文件中:

projects/errtutorial/main.go

package mainimport ("fmt"
)func validateValue(number int) error {if number == 1 {return fmt.Errorf("that's odd")} else if number == 2 {return fmt.Errorf("uh oh")}return nil
}func main() {for num := 1; num <= 3; num++ {fmt.Printf("validating %d... ", num)err := validateValue(num)if err != nil {fmt.Println("there was an error:", err)} else {fmt.Println("valid!")}}
}

程序中的validateValue函数接受一个数字,然后根据它是否被确定为有效值返回一个error。在这个程序中,数字1是无效的,并返回错误that's odd。数字2无效,并返回错误uh ohvalidateValue函数使用fmt.Errorf函数来生成要返回的error值。fmt.Errorf函数很方便地返回错误,因为它允许您使用类似于fmt.Printffmt.Sprintf的格式来格式化错误消息,而不需要将string传递给errors.New

main函数中,for循环将开始迭代从13的每个数字,并将值存储在num变量中。在循环体中,调用fmt.Printf将打印程序当前正在验证的数字。然后,它将调用validateValue函数并传入当前正在验证的数字num,并将错误结果存储在err变量中。最后,如果err不是nil,则意味着在验证过程中发生了错误,并使用fmt.Println打印错误消息。错误检查的else子句将打印"valid!"当没有遇到错误时。

保存更改后,使用go run命令运行程序,并将main.go作为errtutorial目录的参数:

go run main.go

运行该程序的输出将表明,对每个数字都运行了验证,数字1和数字2都返回了相应的错误:

Outputvalidating 1... there was an error: that's odd
validating 2... there was an error: uh oh
validating 3... valid!

查看程序的输出时,你会发现程序试图验证所有三个数字。第一次它说validateValue函数返回了that's odd错误,这是1的值所期望的。下一个值2也显示它返回了一个错误,但这次是uh oh错误。最后,3返回nil作为错误值,这意味着没有错误并且数字是有效的。根据validateValue函数的编写方式,任何非12的值都会返回nil错误值。

在本节中,你使用fmt.Errorf来创建从函数返回的error值。我们还添加了一个错误处理程序,以便在函数返回任何error时打印出错误消息。不过,有时候,知道错误的含义可能很有用,而不仅仅是知道错误发生了。在下一节中,你将学习针对特定情况自定义错误处理。

使用哨兵错误处理特定错误

当你从函数中收到一个error值时,最基本的错误处理是检查error值是否为nil。这将告诉你函数是否有错误,但有时你可能希望针对特定的错误情况自定义错误处理。例如,假设你有代码连接到远程服务器,而你得到的唯一错误信息是“you had a error”。你可能想知道这个错误是因为服务器不可用还是连接凭据无效。如果你知道这个错误意味着用户的凭据是错误的,你可能想让用户立即知道。但是,如果错误意味着服务器不可用,您可能需要尝试重新连接几次,然后才能让用户知道。确定这些错误之间的区别可以让你编写更健壮、更友好的程序。

检查特定类型错误的一种方法可能是使用error类型的error方法从错误中获取消息,并将该值与你要查找的错误类型进行比较。想象一下,在你的程序中,当错误值为uh oh时,你想显示一条消息,而不是 there was an error: uh oh。处理这种情况的一种方法是检查Error方法的返回值,如下所示:

if err.Error() == "uh oh" {// Handle 'uh oh' error.fmt.Println("oh no!")
}

检查err.Error()的字符串值,看看它是否为uh oh,就像上面的代码一样,在这种情况下可以工作。但是,如果程序中其他地方的uh oh错误字符串稍有不同,代码就无法工作。检查错误如果需要更新错误消息本身,这种方式也可能导致对代码的重大更新,因为每个检查错误的地方都需要更新。以以下代码为例:

func giveMeError() error {return fmt.Errorf("uh h")
}err := giveMeError</

http://www.ppmy.cn/news/1274770.html

相关文章

自然语言处理阅读第二弹

HuggingFace 镜像网站模型库 NLP中的自回归模型和自编码模型 自回归&#xff1a;根据上文内容预测下一个可能的单词&#xff0c;或者根据下文预测上一个可能的单词。只能利用上文或者下文的信息&#xff0c;不能同时利用上文和下文的信息。自编码&#xff1a;对输入的句子随…

第18课 SQL入门之使用视图

文章目录 18.1 视图18.1.1 为什么使用视图18.1.2 视图的规则和限制 18.2 创建视图18.2.1 利用视图简化复杂的联结18.2.2 用视图重新格式化检索出的数据18.2.3 用视图过滤不想要的数据18.2.4 使用视图与计算字段 这一课将介绍什么是视图&#xff0c;它们怎样工作&#xff0c;何时…

为什么MCU在ADC采样时IO口有毛刺?

大家在使用MCU内部ADC进行信号采样一个静态电压时&#xff0c;可能在IO口上看到这样的波形。这个时候大家一般会认识是信号源有问题&#xff0c;但仔细观察会发现这个毛刺的频率是和ADC触发频率一样的。 那么为什么MCU在ADC采样时IO口会出现毛刺呢&#xff1f;这个毛刺对结果有…

C# WPF上位机开发(进度条操作)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 软件上面如果一个操作比较缓慢&#xff0c;或者说需要很长的时间&#xff0c;那么这个时候最好添加一个进度条&#xff0c;提示一下当前任务的进展…

【百度PARL】强化学习笔记

文章目录 强化学习基本知识一些框架Value-based的方法Q表格举个例子 强化的概念TD更新 Sarsa算法SampleSarsa Agent类 On_policy vs off_policy函数逼近与神经网络DQN算法DQN创新点DQN代码实现model.pyalgorithm.pyagent.py总结&#xff1a;举个例子 实战 视频&#xff1a;世界…

论文阅读——Painter

Images Speak in Images: A Generalist Painter for In-Context Visual Learning GitHub - baaivision/Painter: Painter & SegGPT Series: Vision Foundation Models from BAAI 可以做什么&#xff1a; 输入和输出都是图片&#xff0c;并且不同人物输出的图片格式相同&a…

案例分享 | 3D开发工具HOOPS加速「全球知名矿业软件」可视化创新与突破!

近日&#xff0c;某全球知名的三维矿业软件公司&#xff08;以下简称“客户”&#xff09;与慧都科技携手合作&#xff0c;慧都将联合数字化合作伙伴Tech Soft 3D-HOOPS&#xff0c;为客户注入3D渲染及可视化核心动力&#xff0c;赋能客户产品实现在地质勘探、地质模型可视化等…

学习Java第74天,Ajax简介

什么是ajax AJAX Asynchronous JavaScript and XML&#xff08;异步的 JavaScript 和 XML&#xff09;。 AJAX 不是新的编程语言&#xff0c;而是一种使用现有标准的新方法。 AJAX 最大的优点是在不重新加载整个页面的情况下&#xff0c;可以与服务器交换数据并更新部分网页…