Go 语言入门指南:错误处理和Error库 | 豆包MarsCode AI刷题

69 阅读3分钟

首先强烈安利AI练中学,方便直观的看到运行结果,不需要自己去配置各类环境,对于初学者,浪费大量时间配置环境是一件很打消学习积极性的事情

由于Go语言的错误处理和Java的不太一样,所以我觉得这个基本特性还是比较有趣的。

1.Go语言错误处理的基本介绍

首先来看一个常见的错误处理模式

func main() {
    conent,err:=ioutil.ReadFile("filepath")
    if err !=nil{
        //错误处理
    }else {
        fmt.Println(string(conent))
    }
}

这类错误判断的代码十分常见的,大部分情况下都是nil,即没有错误,但是如果检查到不是nil,那么说明出现了问题。这是error的接口定义

// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
type error interface {
    Error() string
}

实际上我们能够看到所谓错误实际上只是一个包按着Error()方法的结构体,并且只返回一个string来提示错误所在。所以在实际情况中并不能很好的满足我们错误处理的需求。所以我们往往使用errors库来增加error的功能,这也是实际工程的选择。

2.errors库的基本使用

错误的创建:

func New(message string) error

这里的message是错误对象中包含的信息,这是最基础的功能。在代码中只需要简单的调用即可,他会创建出一个新的错误对象供我们使用,这里的err也只是一个简单地实现了Go语言接口的对象。

package main
​
import (
 "errors"
 "fmt"
)
​
func main() {
 err := errors.New("error")
 fmt.Println(err.Error()) // 打印“error"
}

错误的判断:

func Is(err, target error) bool

Is函数能够帮助我们判断一个错误是否属于某类错误,参数需要一个错误对象,以及一个想要判断的目标错误对象,返回值为一个bool值,相同则返回1,不同则返回0

package main
​
import (
 "errors"
 "fmt"
)
​
var (
 ErrFileEmpty = errors.New("the text file is empty!")
)
​
func main() {
 err := fmt.Errorf("%w: fileName=%s", ErrFileEmpty, "hello.txt")
 if errors.Is(err, ErrFileEmpty) {
  fmt.Println("Yes,it is")
 } else {
  fmt.Println(err)
 }
}

首先定义了一个错误变量 ErrFileEmpty ,用于表示一个文件空白的错误情况,之后利用 fmt.Errorf 函数可以包装该错误,并且然后使用 errors.Is 判断 err 是否等于或包含 ErrFileEmpty。最后会返回一个true

错误断言:As 函数

errors.As 函数用于检查一个错误是否可以被断言为特定的错误类型,成功则将错误包含的值赋给这个特定的错误变量。

func As(err error, target any) bool

err 为当前错误。target 为目标错误,不能为空

package main
​
import (
 "errors"
 "fmt"
)
​
type ErrFileEmpty struct {
 fileName string
}
​
func (e *ErrFileEmpty) Error() string {
 return fmt.Sprintf("fileName=%s", e.fileName)
}
​
func main() {
 var err = &ErrFileEmpty{fileName: "hello.txt"}
 var err1 = &ErrFileEmpty{}
 if errors.As(err, &err1) {
  fmt.Println(err1.fileName) // hello.txt
 } 
}

这个函数与Is的区别主要在于,它在判断的同时会将错误内部的值也赋值给目标错误。,例如我们这里创建了一个ErrFileEmpty的错误err,并且给他赋予了初值。之后创建了一个空白的ErrFileEmpty错误。最后就可以使用As函数对其进行判断和赋值,因为两者是相同的错误,所以最后err1的fileName值就变成为hello.txt,证明赋值成功了。

包装错误:Join 函数

errors.Join 用于包装特定的 errs 并返回一个新的错误对象。需要注意的是 errors.Join 在包装 error 的过程中,会忽略 nil error。

func Join(errs ...error) error

errs 为所给定的错误集,之后返回一个 error 接口类型的经过包装的对象

package main
​
import (
 "errors"
 "fmt"
)
​
func main() {
 err1 := errors.New("errorOne")
 err2 := errors.New("errorTwo")
 err := errors.Join(err1, err2)
 fmt.Println(err)
 fmt.Println(errors.Is(err, err1)) // true
 fmt.Println(errors.Is(err, err2)) // true

程序的运行结果为:

errorOne
errorTWO   //前面两行都属于err的部分
true
true

获取原始错误:Unwrap 函数

errors.Unwrap 函数主要就是解包装,跟上面Join函数正相反

func Unwrap(err error) error

err 为所给定的错误,之后返回一个 error 类型的解包后的对象,注意此时只解一个包

package main
​
import (
 "errors"
 "fmt"
)
​
var (
 ErrFileEmpty = errors.New("file is empty")
)
​
func main() {
 err := fmt.Errorf("%w: fileName=%s", ErrFileEmpty, "hello.txt")
 fmt.Println(err)
 fmt.Println(errors.Unwrap(err))
}

运行结果

file is empty,fileName=hello.txt
file is empty