Golang中错误处理

简介: Golang中错误处理

Golang中错误处理

前言

在起初golang基础并未打扎实直接去学后端的gin框架,但在之前并未学习
go的错误处理,在学习gin时发现在写代码的时候几乎有将近一半的代码都在
进行错误处理日志收集。的确这样做下来在debug的时候会比较的轻松。但是我一点没有系统的看过go中的errors里的方法,只是跟着gin里的项目学
习了zap日志库与errors的一些方法配合使用。今天就看一下Go核心编程里的错误处理。

一、基本概念与使用

error类型其实是一个接口类型,也是一个 Go 语言的内建类型。在这个接口类型的声明中只包含了一个方法Error。Error方法不接受任何参数,但是会返回一个string类型的结果。它的作用是返回错误信息的字符串表示形式。我们使用error类型的方式通常是,在函数声明的结果列表的最后,声明一个该类型的结果,同时在调用这个函数之后,先判断它返回的最后一个结果值是否“不为nil”。
比如代码中所写:


package main

import (
  "errors"
  "fmt"
)

func echo(request string) (response string, err error) {
   
  if request == "" {
   
    err = errors.New("empty request")
    return
  }
  response = fmt.Sprintf("echo: %s", request)
  return
}

func main() {
   
  for _, req := range []string{
   "", "hello!"} {
   
    fmt.Printf("request: %s\n", req)
    resp, err := echo(req)
    if err != nil {
   
      fmt.Printf("error: %s\n", err)
      continue
    }
    fmt.Printf("response: %s\n", resp)
  }
}

代码中两个值得注意的地方
第一,在echo函数和main函数中,都使用到了卫述语句。简单地讲,它就是被用来检查后续操作的前置条件并进行相应处理的语句。也就是我在前言提到的在写代码时铺天盖地的语句。


第二对于echo函数来说,它进行常规操作的前提是:传入的参数值一定要符合要求。而对于调用echo函数的程序来说,进行后续操作的前提就是echo函数的执行不能出错。

二、对于具体错误的判断,Go 语言中都有哪些惯用法?

对于类型在已知范围内的一系列错误值,一般使用类型断言表达式或类型switch语句来判断;


对于已有相应变量且类型相同的一系列错误值,一般直接使用判等操作来判断;


对于没有相应变量且类型未知的一系列错误值,只能使用其错误信息的字符串表示形式来做判断。而这种是我常用的一种方法。


对于第一种情况,如果我们已知错误类型
就有以下案例:


func underlyingError(err error) error {
   
  switch err := err.(type) {
   
  case *os.PathError:
    return err.Err
  case *os.LinkError:
    return err.Err
  case *os.SyscallError:
    return err.Err
  case *exec.Error:
    return err.Err
  }
  return err
}

函数underlyingError的作用是:
获取和返回已知的操作系统相关错误的潜在错误值。其中的类型switch语句中有若干个case子句,分别对应了上述几个错误类型。当它们被选中时,都会把函数参数err的Err字段作为结果值返回。如果它们都未被选中,那么该函数就会直接把参数值作为结果返回,即放弃获取潜在错误值。

三、怎样根据实际情况给予恰当的错误值?

构建错误值体系的基本方式有两种,即:
创建立体的错误类型体系创建扁平的错误值列表


对于立体的错误类型体系。由于在 Go 语言中实现接口是非侵入式的,所以我们可以做得很灵活。

例如在标准库的net代码包中,有一个名为Error的接口类型。它算是内建接口类型error的一个扩展接口,因为error是net.Error的嵌入接口

立体的错误体系可以把一个包的错误类型想象成一棵树,内建接口error就是树的根,而net.Error接口就是一个在根上延伸的第一级非叶子节点。


首先判断它是否是net.Error类型的,也就是说该值是否代表了一个网络相关的错误。如果是,那么我们还可以再进一步判断它的类型是哪一个更具体的错误类型,这样就能知道这个网络相关的错误具体是由于操作不当引起的,还是因为网络地址问题引起的,又或是由于网络协议不正确引起的。
这样就可以模拟出立体的一个体系一层一层的去判断。

用类型建立起树形结构的错误体系,用统一字段建立起可追根溯源的链式错误关联。


对于扁平的错误值列表
当我们只是想预先创建一些代表已知错误的错误值时候,扁平的
错误值列表无疑是最好的选择。

但是问题就来了
由于error是接口类型,所以通过errors.New函数生成的错误值只能被赋给变量,而不能赋给常量,又由于这些代表错误的变量需要给包外代码使用,所以其访问权限只能是公开的。

如果说恶意代码改变了这些公开变量的值,那么程序的功能就必然会受到影响。因为在这种情况下我们往往会通过判等操作来判断拿到的错误值具体是哪一个错误,如果这些公开变量的值被改变了,那么相应的判等操作的结果也会随之改变。

当然对此也有解决的方案:
先私有化此类变量,也就是说,让它们的名称首字母变成小写,然后编写公开的用于获取错误值以及用于判等错误值的函数。
比如,对于错误值os.ErrClosed,先改写它的名称,让其变成os.errClosed,然后再编写ErrClosed函数和IsErrClosed函数。

相关文章
|
6月前
|
存储 Java Go
100天精通Golang(基础入门篇)——第23天:错误处理的艺术: Go语言实战指南
100天精通Golang(基础入门篇)——第23天:错误处理的艺术: Go语言实战指南
26 0
Golang:error包错误处理
Golang:error包错误处理
80 0
|
6月前
|
存储 编译器 Go
Golang 语言的多种变量声明方式和使用场景
Golang 语言的多种变量声明方式和使用场景
32 0
|
6月前
|
缓存 编译器 Go
Golang 语言 vendor 在 GOPATH 和 Modules 中的区别
Golang 语言 vendor 在 GOPATH 和 Modules 中的区别
31 0
|
1月前
|
SQL 前端开发 Go
编程笔记 GOLANG基础 001 为什么要学习Go语言
编程笔记 GOLANG基础 001 为什么要学习Go语言
|
6月前
|
存储 JSON Go
Golang 语言 gRPC 服务怎么同时支持 gRPC 和 HTTP 客户端调用?
Golang 语言 gRPC 服务怎么同时支持 gRPC 和 HTTP 客户端调用?
76 0
|
3月前
|
物联网 Go 网络性能优化
使用Go语言(Golang)可以实现MQTT协议的点对点(P2P)消息发送。MQTT协议本身支持多种消息收发模式
使用Go语言(Golang)可以实现MQTT协议的点对点(P2P)消息发送。MQTT协议本身支持多种消息收发模式【1月更文挑战第21天】【1月更文挑战第104篇】
101 1
|
1天前
|
Go 开发者
Golang深入浅出之-Go语言上下文(context)包:处理取消与超时
【4月更文挑战第23天】Go语言的`context`包提供`Context`接口用于处理任务取消、超时和截止日期。通过传递`Context`对象,开发者能轻松实现复杂控制流。本文解析`context`包特性,讨论常见问题和解决方案,并给出代码示例。关键点包括:1) 确保将`Context`传递给所有相关任务;2) 根据需求选择适当的`Context`创建函数;3) 定期检查`Done()`通道以响应取消请求。正确使用`context`包能提升Go程序的控制流管理效率。
6 1
|
2天前
|
安全 Go 开发者
Golang深入浅出之-Go语言并发编程面试:Goroutine简介与创建
【4月更文挑战第22天】Go语言的Goroutine是其并发模型的核心,是一种轻量级线程,能低成本创建和销毁,支持并发和并行执行。创建Goroutine使用`go`关键字,如`go sayHello("Alice")`。常见问题包括忘记使用`go`关键字、不正确处理通道同步和关闭、以及Goroutine泄漏。解决方法包括确保使用`go`启动函数、在发送完数据后关闭通道、设置Goroutine退出条件。理解并掌握这些能帮助开发者编写高效、安全的并发程序。
12 1