迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 >

Go语言 自定义错误

作者:迹忆客 最近更新:2021/11/10 浏览次数:

Go 语言 错误处理详细介绍 文章中,我们介绍了 Go 中错误是如何使用的,以及如何处理标准库中的错误。 我们还学习了如何从标准库错误中获取更多信息。

本篇主要介绍如何创建我们自己的自定义错误,我们可以在我们创建的函数和包中使用这些错误。 我们还将使用标准库采用的相同技术来提供有关自定义错误的更多详细信息。

使用New函数创建自定义错误

创建自定义错误的最简单方法是使用错误包的 New 函数。

在我们使用 New 函数创建自定义错误之前,让我们首先了解它是如何实现的。 下面代码是 Error Package 中 New 函数的实现。

// Package errors implements functions to manipulate errors.
  package errors

  // New returns an error that formats as the given text.
  func New(text string) error {
      return &errorString{text}
  }

  // errorString is a trivial implementation of error.
  type errorString struct {
      s string
  }

  func (e *errorString) Error() string {
      return e.s
  }

它的实现非常简单。 errorString 是带有单个 string 字段 s 的结构体类型。 并且错误接口的 Error() string方法是使用 errorString 指针接收器实现的。

New 函数接受一个字符串参数,使用该参数创建一个 errorString 类型的值并返回它的地址。 因此一个新的错误被创建并返回。

现在我们知道了 New 函数的工作原理,让我们在我们自己的程序中使用它来创建自定义错误。

我们将创建一个简单的程序来计算圆的面积,如果半径为负,将返回一个错误。

package main

import (  
    "errors"
    "fmt"
    "math"
)

func circleArea(radius float64) (float64, error) {  
    if radius < 0 {
        return 0, errors.New("Area calculation failed, radius is less than zero")
    }
    return math.Pi * radius * radius, nil
}

func main() {  
    radius := -20.0
    area, err := circleArea(radius)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("Area of circle %0.2f", area)
}

运行示例

在上面的程序中,我们检查半径是否小于零。如果小于0,我们为该区域返回零以及相应的错误消息。 如果半径大于 0,则计算面积并返回 nil。

在 main 函数中,我们检查错误是否不为nil。如果不为nil,则打印错误并返回,否则打印圆的面积。

在这个程序中,半径小于零,因此它的输出结果如下。我们也可以点击上面的运行示例直接在线运行查看结果

go 自定义错误

使用 Errorf 给错误增加更多信息

上面的程序运行良好,但如果我们能打印出导致错误的实际半径,那岂不是很好。 这就是 fmt 包的 Errorf 函数派上用场的地方。 此函数根据格式说明符格式化错误并返回一个字符串作为满足错误的值。

让我们使用 Errorf 函数,让程序变得更好。

package main

import (  
    "fmt"
    "math"
)

func circleArea(radius float64) (float64, error) {  
    if radius < 0 {
        return 0, fmt.Errorf("面积计算失败, 半径 %0.2f 小于0", radius)
    }
    return math.Pi * radius * radius, nil
}

func main() {  
    radius := -20.0
    area, err := circleArea(radius)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("圆的面积 %0.2f", area)
}

运行示例

在上面的程序中,Errorf 用于打印导致错误的实际半径。 运行这个程序会输出如下内容,也可以点击上面的运行示例直接在线运行查看结果

go 自定义错误详细信息

使用结构体类型和字段提供有关错误的更多信息

也可以使用将错误接口实现为错误的结构体类型。 这为我们提供了更多的处理错误的灵活性。 在我们的例子中,如果我们要访问导致错误的半径,现在唯一的方法是解析错误描述“面积计算失败, 半径 %0.2f 小于0”。 这不是执行此操作的正确方法,因为如果描述更改,我们的代码将中断。

我们将创建一个实现错误接口的结构体类型,并使用其字段提供有关错误的更多信息。

第一步是创建一个结构体类型来表示错误。 错误类型的命名约定是名称应以文本 Error 结尾。 所以让我们将我们的结构体类型命名为 areaError

type areaError struct {  
    err    string
    radius float64
}

上面的结构体类型有一个字段 radius 来存储导致错误的半径值,而 err 字段存储实际的错误消息。

下一步是实现错误接口。

func (e *areaError) Error() string {  
    return fmt.Sprintf("半径 %0.2f: %s", e.radius, e.err)
}

在上面的代码片段中,我们使用指针接收器 *areaError 实现了错误接口的 Error() string 方法。 此方法打印半径和错误描述。

让我们通过编写 main 函数和 circleArea 函数来完成程序。

package main

import (  
    "fmt"
    "math"
)

type areaError struct {  
    err    string
    radius float64
}

func (e *areaError) Error() string {  
    return fmt.Sprintf("半径 %0.2f: %s", e.radius, e.err)
}

func circleArea(radius float64) (float64, error) {  
    if radius < 0 {
        return 0, &areaError{"radius is negative", radius}
    }
    return math.Pi * radius * radius, nil
}

func main() {  
    radius := -20.0
    area, err := circleArea(radius)
    if err != nil {
        if err, ok := err.(*areaError); ok {
            fmt.Printf("半径 %0.2f 小于0", err.radius)
            return
        }
        fmt.Println(err)
        return
    }
    fmt.Printf("rectangle1 的面积 %0.2f", area)
}

运行示例

在上面的程序中的 circleArea 用于计算圆的面积。 此函数首先检查半径是否小于零,如果是,则使用导致错误的半径和相应的错误消息创建一个 areaError 类型的值,然后返回它的地址和 0 作为面积。 因此,我们提供了有关错误的更多信息,在本例中,使用自定义错误结构的字段存储导致错误的半径的值。

如果半径不为负,则此函数计算并返回该面积以及错误nil。

在 main 函数中我们试图找到半径为 -20 的圆的面积。 由于半径小于零,将返回错误。

我们检查错误是否不为 nil。 下一行中,我们判断它是否是 *areaError。 如果错误是 *areaError 类型的,我们将得到导致错误的半径。使用err.radius,打印自定义错误信息并从程序中返回。

上面的程序输出如下所示

go 使用结构体自定义错误

使用结构体中的方法提供有关错误的更多信息

接下来我们将编写一个计算矩形面积的程序。 如果长度或宽度小于零,该程序将打印错误。

第一步是创建一个表示错误的结构体。

type areaError struct {  
    err    string // 错误描述
    length float64 // 引发错误的长度的值
    width  float64 // 引发错误的宽度的值
}

现在我们有了错误类型,让我们实现错误接口并在错误类型上添加几个方法来提供有关错误的更多信息。

func (e *areaError) Error() string {  
    return e.err
}

func (e *areaError) lengthNegative() bool {  
    return e.length < 0
}

func (e *areaError) widthNegative() bool {  
    return e.width < 0
}

在上面的代码片段中,我们从 Error() string 方法返回错误的描述。 当长度小于零时,lengthNegative() bool 方法返回真,当宽度小于零时,widthNegative() bool 方法返回真。 这两种方法提供了更多关于错误的信息,在这种情况下,它们说明面积计算是否因为长度为负或宽度为负而失败。 因此,我们使用了结构体的方法来提供有关错误的更多信息。

下一步是编写面积计算函数。

func rectArea(length, width float64) (float64, error) {  
    err := ""
    if length < 0 {
        err += "长度小于0"
    }
    if width < 0 {
        if err == "" {
            err = "宽度小于0"
        } else {
            err += ", 宽度小于0"
        }
    }
    if err != "" {
        return 0, &areaError{err, length, width}
    }
    return length * width, nil
}

上面的 rectArea 函数检查长度或宽度是否小于零,如果是,则返回错误消息,否则返回矩形的面积,错误为 nil。

最后让我们来编写 main 函数

func main() {  
    length, width := -5.0, -9.0
    area, err := rectArea(length, width)
    if err != nil {
        if err, ok := err.(*areaError); ok {
            if err.lengthNegative() {
                fmt.Printf("error: 长度 %0.2f 小于0\n", err.length)

            }
            if err.widthNegative() {
                fmt.Printf("error: 宽度 %0.2f 小于0\n", err.width)

            }
            return
        }
        fmt.Println(err)
        return
    }
    fmt.Println("矩形的面积 ", area)
}

在 main 函数中,我们检查错误是否不为nil。如果它不是 nil,我们判断它是否为 *areaError。 然后使用 lengthNegative() 和 widthNegative() 方法,检查错误是由于长度为负数还是宽度为负数。 我们打印相应的错误信息并从程序中返回。 因此,我们使用了Error结构体的方法来提供有关错误的更多信息。

如果没有错误,将打印矩形的面积。

下面是完整的程序

package main

import "fmt"

type areaError struct {  
    err    string // 错误描述
    length float64 // 引发错误的长度的值
    width  float64 // 引发错误的宽度的值
}

func (e *areaError) Error() string {  
    return e.err
}

func (e *areaError) lengthNegative() bool {  
    return e.length < 0
}

func (e *areaError) widthNegative() bool {  
    return e.width < 0
}

func rectArea(length, width float64) (float64, error) {  
    err := ""
    if length < 0 {
        err += "长度小于0"
    }
    if width < 0 {
        if err == "" {
            err = "宽度小于0"
        } else {
            err += ", 宽度小于0"
        }
    }
    if err != "" {
        return 0, &areaError{err, length, width}
    }
    return length * width, nil
}

func main() {  
    length, width := -5.0, -9.0
    area, err := rectArea(length, width)
    if err != nil {
        if err, ok := err.(*areaError); ok {
            if err.lengthNegative() {
                fmt.Printf("error: 长度 %0.2f 小于0\n", err.length)

            }
            if err.widthNegative() {
                fmt.Printf("error: 宽度 %0.2f 小于0\n", err.width)

            }
            return
        }
        fmt.Println(err)
        return
    }
    fmt.Println("矩形的面积 ", area)
}

运行示例

上面的程序输出如下

go 计算矩形面积

关于Go语言的基础知识可以查看我们的Go教程

除非注明转载,本站文章均为原创或翻译,欢迎转载,转载请以链接形式注明出处

本文地址:

迹忆客

专注技术分享,项目实战分享!

技术宅 乐于分享 7年编程经验
社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

热门文章

教程更新

热门标签

Go