Go语言 自定义错误
在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,则打印错误并返回,否则打印圆的面积。
在这个程序中,半径小于零,因此它的输出结果如下。我们也可以点击上面的运行示例直接在线运行查看结果
使用 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 用于打印导致错误的实际半径。 运行这个程序会输出如下内容,也可以点击上面的运行示例直接在线运行查看结果
使用结构体类型和字段提供有关错误的更多信息
也可以使用将错误接口实现为错误的结构体类型。 这为我们提供了更多的处理错误的灵活性。 在我们的例子中,如果我们要访问导致错误的半径,现在唯一的方法是解析错误描述“面积计算失败, 半径 %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,打印自定义错误信息并从程序中返回。
上面的程序输出如下所示
使用结构体中的方法提供有关错误的更多信息
接下来我们将编写一个计算矩形面积的程序。 如果长度或宽度小于零,该程序将打印错误。
第一步是创建一个表示错误的结构体。
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教程
相关文章
MySQL 错误 Error Server PID File Could Not Be Found 解决
发布时间:2023/05/09 浏览次数:98 分类:MySQL
-
在这篇文章中,我们将研究错误! Error Server PID File Could Not Be Found! 在 MySQL 及其解决方案中有充分的解释。
使用 C 语言中的 goto 语句
发布时间:2023/05/07 浏览次数:79 分类:C语言
-
本文介绍了如何在 C 语言中使用 goto 语句。使用 goto 语句在 C 语言中实现循环 goto 关键字是 C 语言的一部分,它提供了一个做无条件跳转的结构。
Django 中的 Slug
发布时间:2023/05/04 浏览次数:173 分类:Python
-
本篇文章旨在定义一个 slug 以及我们如何使用 slug 字段在 Python 中使用 Django 获得独特的帖子。
在 Django 中按降序过滤查询集中的项目
发布时间:2023/05/04 浏览次数:157 分类:Python
-
在这个讲解中,学习如何借助 Django 中的 order_by() 方法按降序过滤出查询集中的项目。
Django ALLOWED_HOSTS 介绍
发布时间:2023/05/04 浏览次数:181 分类:Python
-
本文展示了如何创建您的 Django 网站,为公开发布做好准备,如何设置 ALLOWED_HOSTS 以及如何在使用 Django 进行 Web 部署期间修复预期的主要问题。
Django 中的 Select_related 方法
发布时间:2023/05/04 浏览次数:129 分类:Python
-
本文介绍了什么是查询集,如何处理这些查询以及我们如何利用 select_related() 方法来过滤 Django 中相关模型的查询。
使用 Post 请求将数据发送到 Django 服务器
发布时间:2023/05/04 浏览次数:159 分类:Python
-
在这篇关于Django的讲解中,我们简要介绍了post和get请求以及如何在Django中用post实现CSRF token。
Django 返回 JSON
发布时间:2023/05/04 浏览次数:106 分类:Python
-
在与我们的讨论中,我们简要介绍了 JSON 格式,并讨论了如何借助 Django 中的 JsonResponse 类将数据返回为 JSON 格式。