c语言编程笔录

首页 >   > 笔记大全

笔记大全

Golang函数的Error类型应用技巧

更新时间:2023-07-13

Golang函数的Error类型应用技巧

在编写 Golang 代码的过程中,我们经常需要在函数中返回错误信息。Go语言的 error 类型是一个接口类型,是内置包中的一个预定义接口,也是非常常见的一种类型。本文将介绍 Error 类型的应用技巧,帮助读者更好地利用该类型进行错误处理。

1. 使用errors.New()函数

errors.New()函数是非常简单且有用的构造函数,可以创建一个实现了 error 接口的简单类型。

    package main

    import (
      "errors"
      "fmt"
    )

    func divide(num1 int, num2 int) (int, error) {
      if num2 == 0 {
        err := errors.New("cannot divide by zero")
        return 0, err
      }
      return num1 / num2, nil
    }

    func main() {
      res, err := divide(4, 2)
      if err != nil {
        fmt.Println(err)
      } else {
        fmt.Println(res)
      }
    }
  

上述代码演示了如何使用 errors.New() 函数创建一个包含错误信息的 error 对象。如果函数成功执行,则返回值为 nil,并输出结果,否则返回错误信息。

2. 自定义 Error 类型

对于一些重要的逻辑或应用程序,在使用 errors.New() 函数定义 error 类型时可能不够灵活,这时我们可以定义一个自定义的 Error 类型,以便可以更好地描述错误信息。

    package main

    import (
      "fmt"
    )

    type DivisionError struct {
      dividend int
      divisor  int
    }

    func (de DivisionError) Error() string {
      strFormat := `Cannot proceed, the divisor is zero.
        dividend: %d
        divisor: 0`
      return fmt.Sprintf(strFormat, de.dividend)
    }

    func divide(num1 int, num2 int) (int, error) {
      if num2 == 0 {
        dError := DivisionError{dividend: num1, divisor: num2}
        return 0, dError
      }
      return num1 / num2, nil
    }

    func main() {
      res, err := divide(4, 0)
      if err != nil {
        fmt.Println(err)
      } else {
        fmt.Println(res)
      }
    }
  

上述代码中,我们定义了一个叫做 DivisionError 的结构体,其包含被除数和除数两个参数。我们用 Error() 方法实现了 error 接口,由此定义了一个自定义的 Error 类型。在 divide 函数中,如果除数为 0,则返回这个自定义的 Error 类型。

3. 使用 panic 来处理错误

panic 是 Golang 中常用的错误处理方式之一,是一种高度定制化的方法,在某些情况下可能更加方便,但不应该经常使用,因为它会导致程序崩溃。

    package main

    import "fmt"

    func divide(num1 int, num2 int) int {
      if num2 == 0 {
        panic("cannot divide by zero")
      }
      return num1 / num2
    }

    func main() {
      defer func() {
        if err := recover(); err != nil {
          fmt.Println(err)
        }
      }()
      res := divide(4, 0)
      fmt.Println(res)
    }
  

上述代码中,我们使用 panic 抛出异常,在 main 函数中使用 recover 捕获异常并输出错误信息。

4. Wrap 和 Unwrap 方法

从 Golang 1.13 版本开始,内置的 errors.New() 和 fmt.Errorf() 函数提供了一个额外的附加参数,称为“wrap error”。这个 wrap error 提供了更完整的错误信息,包括该错误的根本原因。使用 wrap error 可以轻松地查看特定错误类型的堆栈跟踪。

    package main

    import (
      "errors"
      "fmt"
      "io/ioutil"
    )

    func readFile() error {
      _, err := ioutil.ReadFile("test.txt")
      if err != nil {
        return fmt.Errorf("readFile: %w", err)
      }
      return nil
    }

    func main() {
      err := readFile()
      if err != nil {
        if wrappedErr := errors.Unwrap(err); wrappedErr != nil {
          fmt.Printf("original error: %T %v\n", wrappedErr, wrappedErr)
        }
        fmt.Printf("readFile error: %T %v", err, err)
      }
    }
  

上述代码中,我们首先读取一个不存在的文件,然后将错误信息写入日志,并返回错误信息。在 main 函数中,我们通过 errors.Unwrap() 来访问 wrapped error 来查看原始错误类型。如果发生了错误,我们将打印错误和错误类型。

总结

学习 Error 类型的应用技巧是 Golang 的基础知识之一,仅仅是代码处理过程中错误的简单描述,而它的使用却有很多细节内容。Error 类型不仅允许我们返回在函数调用中的错误,还包括创建自定义的错误类型,抛出处理 panic中断异常等特殊情况。我们要根据操作的具体场景,聚焦错误的根源,以便更好地辅导我们进行异常处理。.