扫码订阅《 Go语言基础》或入驻星球,即可阅读文章!

GOLANG ROADMAP

阅读模式

  • 沉浸
  • 自动
  • 日常
首页
Go学习
  • Go学院

    • Go小课
    • Go小考
    • Go实战
    • 精品课
  • Go宝典

    • 在线宝典
    • B站精选
    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
  • Go下载

    • 视频资源
    • 文档资源
Go求职
  • 求职服务

    • 内推互助
    • 求职助力
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
Go友会
  • 城市
  • 校园
推广返利 🤑
实验区
  • Go周边
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
author-avatar

GOLANG ROADMAP


首页
Go学习
  • Go学院

    • Go小课
    • Go小考
    • Go实战
    • 精品课
  • Go宝典

    • 在线宝典
    • B站精选
    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
  • Go下载

    • 视频资源
    • 文档资源
Go求职
  • 求职服务

    • 内推互助
    • 求职助力
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
Go友会
  • 城市
  • 校园
推广返利 🤑
实验区
  • Go周边
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
  • 课程介绍

    • 《Go语言基础》
  • 入门简介

  • 基础语法

  • 流程语句

  • 数组和切片

  • Map

  • string

  • 函数

  • 指针

  • 结构体

  • 方法

  • 接口

  • 错误

    • 第1节:什么是错误
    • 第2节:错误类型表示
    • 第3节:自定义错误
    • 第4节:panic()和recover()
    • 第5节:异常和错误

扫码订阅《 Go语言基础》或入驻星球,即可阅读文章!

第3节:自定义错误


GOLANG ROADMAP

创建自定义错误可以使用errors包下的New()函数,以及fmt包下的:Errorf()函数。

//errors包:
func New(text string) error {}

//fmt包:
func Errorf(format string, a ...interface{}) error {}
1
2
3
4
5

在使用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
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

既然我们知道了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)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

运行结果:

Area calculation failed, radius is less than zero 
1

使用Errorf向错误添加更多信息

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

使用Errorf函数,修改程序。

package main

import (  
    "fmt"
    "math"
)

func circleArea(radius float64) (float64, error) {  
    if radius < 0 {
        return 0, fmt.Errorf("Area calculation failed, radius %0.2f is less than zero", 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("Area of circle %0.2f", area)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

运行结果:

Area calculation failed, radius -20.00 is less than zero  
1

使用struct类型和字段提供关于错误的更多信息

还可以使用将错误接口实现为错误的struct类型。这给我们提供了更多的错误处理的灵活性。在我们的示例中,如果我们想要访问导致错误的半径,那么现在唯一的方法是解析错误描述区域计算失败,半径-20.00小于零。这不是一种正确的方法,因为如果描述发生了变化,我们的代码就会中断。

我们将使用在前面的教程中解释的标准库的策略,在“断言底层结构类型并从struct字段获取更多信息”,并使用struct字段来提供对导致错误的半径的访问。我们将创建一个实现错误接口的struct类型,并使用它的字段来提供关于错误的更多信息。

第一步是创建一个struct类型来表示错误。错误类型的命名约定是,名称应该以文本Error结束。让我们把struct类型命名为areaError

type areaError struct {  
    err    string
    radius float64
}
1
2
3
4

上面的struct类型有一个字段半径,它存储了为错误负责的半径的值,并且错误字段存储了实际的错误消息。

下一步,是实现error 接口

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

在上面的代码片段中,我们使用一个指针接收器区域错误来实现错误接口的Error() string方法。这个方法打印出半径和错误描述。

package main

import (  
    "fmt"
    "math"
)

type areaError struct {  
    err    string
    radius float64
}

func (e *areaError) Error() string {  
    return fmt.Sprintf("radius %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("Radius %0.2f is less than zero", err.radius)
            return
        }
        fmt.Println(err)
        return
    }
    fmt.Printf("Area of circle %0.2f", area)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

程序输出:

Radius -20.00 is less than zero
1

使用结构类型的方法提供关于错误的更多信息

在本节中,我们将编写一个程序来计算矩形的面积。如果长度或宽度小于0,这个程序将输出一个错误。

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

type areaError struct {  
    err    string //error description
    length float64 //length which caused the error
    width  float64 //width which caused the error
}
1
2
3
4
5

上面的错误结构类型包含一个错误描述字段,以及导致错误的长度和宽度。

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

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
}
1
2
3
4
5
6
7
8
9
10
11

在上面的代码片段中,我们返回Error() string 方法的错误描述。当长度小于0时,lengthNegative() bool方法返回true;当宽度小于0时,widthNegative() bool方法返回true。这两种方法提供了更多关于误差的信息,在这种情况下,他们说面积计算是否失败,因为长度是负的,还是宽度为负的。因此,我们使用了struct错误类型的方法来提供更多关于错误的信息。

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

func rectArea(length, width float64) (float64, error) {  
    err := ""
    if length < 0 {
        err += "length is less than zero"
    }
    if width < 0 {
        if err == "" {
            err = "width is less than zero"
        } else {
            err += ", width is less than zero"
        }
    }
    if err != "" {
        return 0, &areaError{err, length, width}
    }
    return length * width, nil
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

上面的rectArea函数检查长度或宽度是否小于0,如果它返回一个错误消息,则返回矩形的面积为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: length %0.2f is less than zero\n", err.length)

            }
            if err.widthNegative() {
                fmt.Printf("error: width %0.2f is less than zero\n", err.width)

            }
        }
        fmt.Println(err)
        return
    }
    fmt.Println("area of rect", area)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

运行结果:

error: length -5.00 is less than zero  
error: width -9.00 is less than zero 
1
2