我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Go语言的错误处理方法有哪些

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Go语言的错误处理方法有哪些

这篇文章主要介绍了Go语言的错误处理方法有哪些的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Go语言的错误处理方法有哪些文章都会有所收获,下面我们一起来看看吧。

与其他语言的快速比较

在 Go 中,所有的错误都是值。因为这点,相当多的函数***会返回一个 error, 看起来像这样:

func (s *SomeStruct) Function() (string, error)

因此这导致调用代码通常会使用 if 语句来检查它们:

bytes, err := someStruct.Function()if err != nil {  // Process error}

另外一种方法,是在其他语言中,如 Java、C#、Javascript、Objective C、Python 等使用的 try-catch  模式。如下你可以看到与先前的 Go 示例类似的 Java 代码,声明 throws 而不是返回 error:

public String function() throws Exception

它使用的是 try-catch 而不是 if err != nil:

try {  String result = someObject.function()  // continue logic}catch (Exception e) {  // process exception}

当然,还有其他的不同。例如,error 不会使你的程序崩溃,然而 Exception 会。还有其他的一些,在本篇中会专门提到这些。

实现集中式错误处理

退一步,让我们看看为什么要在一个集中的地方处理错误,以及如何做到。

大多数人或许会熟悉的一个例子是 web 服务 - 如果出现了一些未预料的的服务端错误,我们会生成一个 5xx 错误。在 Go  中,你或许会这么实现:

func init() {    http.HandleFunc("/users", viewUsers)    http.HandleFunc("/companies", viewCompanies)} func viewUsers(w http.ResponseWriter, r *http.Request) {    user // some code    if err := userTemplate.Execute(w, user); err != nil {        http.Error(w, err.Error(), 500)    }} func viewCompanies(w http.ResponseWriter, r *http.Request) {    companies = // some code    if err := companiesTemplate.Execute(w, companies); err != nil {        http.Error(w, err.Error(), 500)    }}

这并不是一个好的解决方案,因为我们不得不重复地在所有的处理函数中处理错误。为了能更好地维护,***能在一处地方处理错误。幸运的是,在 Go  语言的官方博客中,Andrew Gerrand 提供了一个替代方法,可以***地实现。我们可以创建一个处理错误的 Type:

type appHandler func(http.ResponseWriter, *http.Request) error func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {    if err := fn(w, r); err != nil {        http.Error(w, err.Error(), 500)    }}

这可以作为一个封装器来修饰我们的处理函数:

func init() {    http.Handle("/users", appHandler(viewUsers))    http.Handle("/companies", appHandler(viewCompanies))}

接着我们需要做的是修改处理函数的签名来使它们返回 errors。这个方法很好,因为我们做到了 DRY 原则,并且没有重复使用不必要的代码 -  现在我们可以在单独一个地方返回默认错误了。

错误上下文

在先前的例子中,我们可能会收到许多潜在的错误,它们中的任何一个都可能在调用堆栈的许多环节中生成。这时候事情就变得棘手了。

为了演示这点,我们可以扩展我们的处理函数。它可能看上去像这样,因为模板执行并不是唯一一处会发生错误的地方:

func viewUsers(w http.ResponseWriter, r *http.Request) error {    user, err := findUser(r.formValue("id"))     if err != nil {      return err;    }    return userTemplate.Execute(w, user);}

调用链可能会相当深,在整个过程中,各种错误可能在不同的地方实例化。Russ Cox的这篇文章解释了如何避免遇到太多这类问题的***实践:

“在 Go 中错误报告的部分约定是函数包含相关的上下文,包括正在尝试的操作(比如函数名和它的参数)。”

这个给出的例子是对 OS 包的一个调用:

err := os.Remove("/tmp/nonexist")fmt.Println(err)

它会输出:

remove /tmp/nonexist: no such file or directory

总结一下,执行后,输出的是被调用的函数、给定的参数、特定的出错信息。当在其他语言中创建一个 Exception 消息时,你也可以遵循这个实践。如果我们在  viewUsers 处理中坚持这点,那么几乎总是能明确错误的原因。

问题来自于那些不遵循这个***实践的人,并且你经常会在第三方的 Go 库中看到这些消息:

Oh no I broke

这没什么帮助 - 你无法了解上下文,这使得调试很困难。更糟糕的是,当这些错误被忽略或返回时,这些错误会被备份到堆栈中,直到它们被处理为止:

if err != nil {  return err}

这意味着错误何时发生并没有被传递出来。

应该注意的是,所有这些错误都可以在 Exception 驱动的模型中发生 - 糟糕的错误信息、隐藏异常等。那么为什么我认为该模型更有用?

即便我们在处理一个糟糕的异常消息,我们仍然能够了解它发生在调用堆栈中什么地方。因为堆栈跟踪,这引发了一些我对 Go 不了解的部分 - 你知道 Go 的  panic 包含了堆栈追踪,但是 error 没有。我推测可能是 panic  会使你的程序崩溃,因此需要一个堆栈追踪,而处理错误并不会,因为它会假定你在它发生的地方做一些事。

所以让我们回到之前的例子 - 一个有糟糕错误信息的第三方库,它只是输出了调用链。你认为调试会更容易吗?

panic: Oh no I broke[signal 0xb code=0x1 addr=0x0 pc=0xfc90f] goroutine 1103 [running]:panic(0x4bed00, 0xc82000c0b0)/usr/local/go/class="lazy" data-src/runtime/panic.go:481 +0x3e6github.com/Org/app/core.(_app).captureRequest(0xc820163340, 0x0, 0x55bd50, 0x0, 0x0)/home/ubuntu/.go_workspace/class="lazy" data-src/github.com/Org/App/core/main.go:313 +0x12cfgithub.com/Org/app/core.(_app).processRequest(0xc820163340, 0xc82064e1c0, 0xc82002aab8, 0x1)/home/ubuntu/.go_workspace/class="lazy" data-src/github.com/Org/App/core/main.go:203 +0xb6github.com/Org/app/core.NewProxy.func2(0xc82064e1c0, 0xc820bb2000, 0xc820bb2000, 0x1)/home/ubuntu/.go_workspace/class="lazy" data-src/github.com/Org/App/core/proxy.go:51 +0x2agithub.com/Org/app/core/vendor/github.com/rusenask/goproxy.FuncReqHandler.Handle(0xc820da36e0, 0xc82064e1c0, 0xc820bb2000, 0xc5001, 0xc820b4a0a0)/home/ubuntu/.go_workspace/class="lazy" data-src/github.com/Org/app/core/vendor/github.com/rusenask/goproxy/actions.go:19 +0x30

我认为这可能是 Go 的设计中被忽略的东西 - 不是所有语言都不会忽视的。

如果我们使用 Java 作为一个随意的例子,其中人们犯的一个最愚蠢的错误是不记录堆栈追踪:

LOGGER.error(ex.getMessage()) // 不记录堆栈追踪LOGGER.error(ex.getMessage(), ex) // 记录堆栈追踪

但是 Go 似乎在设计中就没有这个信息。

在获取上下文信息方面 - Russ 还提到了社区正在讨论一些潜在的接口用于剥离上下文错误。关于这点,了解更多或许会很有趣。

堆栈追踪问题解决方案

幸运的是,在做了一些查找后,我发现了这个出色的 Go 错误库来帮助解决这个问题,来给错误添加堆栈跟踪:

if errors.Is(err, crashy.Crashed) {  fmt.Println(err.(*errors.Error).ErrorStack())}

不过,我认为这个功能如果能成为语言的***类公民first class  citizenship将是一个改进,这样你就不必做一些类型修改了。此外,如果我们像先前的例子那样使用第三方库,它可能没有使用 crashy -  我们仍有相同的问题。

我们对错误应该做什么?

我们还必须考虑发生错误时应该发生什么。这一定有用,它们不会让你的程序崩溃,通常也会立即处理它们:

err := method()if err != nil {  // some logic that I must do now in the event of an error!}

如果我们想要调用大量方法,它们会产生错误,然后在一个地方处理所有错误,这时会发生什么?看上去像这样:

err := doSomething()if err != nil {  // handle the error here} func doSomething() error {  err := someMethod()  if err != nil {    return err  }  err = someOther()  if err != nil {    return err  }  someOtherMethod()}

这感觉有点冗余,在其他语言中你可以将多条语句作为一个整体处理。

try {  someMethod()  someOther()  someOtherMethod()}catch (Exception e) {  // process exception}

或者只要在方法签名中传递错误:

public void doSomething() throws SomeErrorToPropogate {  someMethod()  someOther()  someOtherMethod()}

我个人认为这两个例子实现了一件事情,只是 Exception 模式更少冗余,更加弹性。如果有什么的话,我觉得 if err!= nil  感觉像样板。也许有一种方法可以清理?

将失败的多条语句做为一个整体处理错误

首先,我做了更多的阅读,并在 Rob Pike 写的 Go 博客中发现了一个比较务实的解决方案。

他定义了一个封装了错误的方法的结构体:

type errWriter struct {    w   io.Writer    err error} func (ew *errWriter) write(buf []byte) {    if ew.err != nil {        return    }    _, ew.err = ew.w.Write(buf)}

让我们这么做:

ew := &errWriter{w: fd}ew.write(p0[a:b])ew.write(p1[c:d])ew.write(p2[e:f])// and so onif ew.err != nil {    return ew.err}

这也是一个很好的方案,但是我感觉缺少了点什么 -  因为我们不能重复使用这个模式。如果我们想要一个含有字符串参数的方法,我们就不得不改变函数签名。或者如果我们不想执行写操作会怎样?我们可以尝试使它更通用:

type errWrapper struct {    err error}
func (ew *errWrapper) do(f func() error) {    if ew.err != nil {        return    }    ew.err = f();}

但是我们有一个相同的问题,如果我们想要调用含有不同参数的函数,它就无法编译了。然而你可以简单地封装这些函数调用:

w := &errWrapper{} w.do(func() error {    return someFunction(1, 2);}) w.do(func() error {    return otherFunction("foo");}) err := w.err if err != nil {// process error here}

关于“Go语言的错误处理方法有哪些”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Go语言的错误处理方法有哪些”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Go语言的错误处理方法有哪些

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

下载Word文档

猜你喜欢

Go语言的错误处理方法有哪些

这篇文章主要介绍了Go语言的错误处理方法有哪些的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Go语言的错误处理方法有哪些文章都会有所收获,下面我们一起来看看吧。与其他语言的快速比较在 Go 中,所有的错误都是值
2023-06-17

go语言错误处理的方法有哪些

Go语言中的错误处理方法有以下几种:1. 返回错误值:函数可以返回一个额外的错误值,通常是一个error类型的值,用于表示函数执行过程中是否发生了错误。调用者可以根据返回的错误值进行相应的处理。```gofunc divide(a, b i
2023-08-15

Go语言的错误处理方式

这篇文章主要介绍“Go语言的错误处理方式”,在日常操作中,相信很多人在Go语言的错误处理方式问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Go语言的错误处理方式”的疑惑有所帮助!接下来,请跟着小编一起来学习吧
2023-06-15

mybatis错误处理的方法有哪些

MyBatis 提供了以下几种错误处理的方法:1. 异常映射:MyBatis 可以将底层数据库访问引发的异常映射为应用程序定义的异常。通过配置异常映射,可以将底层数据库异常转化为更具有语义的应用程序异常,从而更容易处理和理解。2. 异常捕获
2023-09-13

java错误处理的方法有哪些

Java错误处理的方法有以下几种:1. 异常捕获和处理:使用try-catch语句来捕获和处理异常。在try块中编写可能抛出异常的代码,然后使用catch块来捕获并处理异常。2. 异常声明:在方法签名中声明可能抛出的异常,然后由调用者处理。
2023-08-26

python错误处理的方法有哪些

在Python中,常用的错误处理方法有以下几种:try-except语句:用于捕获和处理异常。代码放在try代码块中执行,如果出现异常,则会跳转到对应的except代码块进行处理。try:# 代码块except 错误类型 as 变量:#
2023-10-26

不同语言中错误处理与Go语言错误处理的差异

不同编程语言的错误处理方式不同,如 javascript 使用 try...catch 块,java 使用异常类。go 语言使用错误值,一种表示错误详细信息的接口类型。函数可以通过返回错误值来指示操作失败。可以使用 if 语句或 error
不同语言中错误处理与Go语言错误处理的差异
2024-04-12

go语言内存管理的方法有哪些

Go语言内存管理的方法有以下几种:1. 垃圾回收(Garbage Collection):Go语言使用自动垃圾回收机制来管理内存。垃圾回收器会自动检测不再使用的内存,并将其释放。Go语言的垃圾回收器使用了标记-清除算法和三色标记法,可以在不
2023-09-27

c语言常见的语法错误有哪些

C语言常见的语法错误包括:1. 缺少分号:在语句结束处没有加上分号;2. 括号不匹配:括号没有正确配对,例如缺少左括号或右括号;3. 大小写错误:C语言是区分大小写的,因此标识符的大小写必须一致;4. 变量未声明:使用了未声明的变量或函数;
2023-08-19

Go错误处理的基本规则有哪些

这篇文章主要讲解了“Go错误处理的基本规则有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Go错误处理的基本规则有哪些”吧!规则1-不要忽略错误迟早你的函数将返回失败,你将花费大量时间来
2023-06-03

go语言扩容方法有哪些

这篇文章主要介绍“go语言扩容方法有哪些”,在日常操作中,相信很多人在go语言扩容方法有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”go语言扩容方法有哪些”的疑惑有所帮助!接下来,请跟着小编一起来学习吧
2023-07-05

go语言有哪些好处

这篇文章主要介绍“go语言有哪些好处”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“go语言有哪些好处”文章能帮助大家解决问题。go语言的好处:1、可直接编译成机器码,不依赖其他库;2、静态类型语言,
2023-07-05

go语言中的输出方法有哪些

这篇文章主要介绍了go语言中的输出方法有哪些的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇go语言中的输出方法有哪些文章都会有所收获,下面我们一起来看看吧。输出方法:1、Print()函数,可输出到控制台(不接
2023-07-04

c语言字符串处理的方法有哪些

C语言字符串处理的方法有以下几种:1. 使用字符数组:可以通过定义一个字符数组来存储字符串,然后使用相关的字符串处理函数来对字符串进行操作,如strcpy、strcat、strcmp等。2. 使用指针:C语言中字符串实际上是一个字符数组,可
2023-08-30

c语言处理字符串的方法有哪些

C语言处理字符串的方法有以下几种:1. 字符串赋值:使用strcpy函数将一个字符串赋值给另一个字符串。2. 字符串连接:使用strcat函数将两个字符串连接起来。3. 字符串比较:使用strcmp函数比较两个字符串是否相等。4. 字符串长
2023-08-24

Golang中的错误处理方式有哪些

这篇文章主要讲解了“Golang中的错误处理方式有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang中的错误处理方式有哪些”吧!错误类型在Golang中,错误类型是错误处理的基本
2023-07-06

go语言中常见的并发编程错误有哪些

这篇“go语言中常见的并发编程错误有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“go语言中常见的并发编程错误有哪些”文
2023-06-17

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录