博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[译] Part 31: golang 中的自定义 error
阅读量:5906 次
发布时间:2019-06-19

本文共 7404 字,大约阅读时间需要 24 分钟。

  • 原文地址:
  • 原文作者:
  • 译者:咔叽咔叽 转载请注明出处。

在上一个教程中,我们学习了在 Go 语言中的error是如何表示的以及怎么用标准库处理error。我们还学习了如何从标准库中提取更多的error信息。

本教程介绍如何在我们的函数和包中使用自己定义的error,我们将使用标准库使用的相同技术来提供有关我们的自定义error的更多信息。

使用New函数创建自定义error

创建自定义error最简单的方法是使用errors包的函数。

在我们使用New函数创建自定义error之前,我们先来了解它是如何实现的。下面提供了中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是一个带有单个字符串s的结构类型。error接口的Error方法是在第 14 行使用errorString指针接收器实现的。

第 5 行的New函数接受一个字符串参数,使用该参数创建一个errorString类型的值并返回它的地址,一个新的error就完成了。

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

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

package mainimport (    "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)}复制代码

在上面的程序中,我们在第 10 行检查半径是否小于零。如果是,则返回 0 以及相应的error内容。在第 13 行中,如果半径大于 0,则计算面积并返回值为nilerror

在 main 函数中,我们在第 19 行检查error是否为nil。如果不是nil,就打印错误并返回,否则打印区域的面积。

在这个程序中,半径小于零,因此它将打印,

Area calculation failed, radius is less than zero复制代码

使用Errorferror增加更多的信息

上面的程序效果还不错,但是如果我们要想打印确切的错误信息就有点吃力了。这种场景fmt包的Errorf函数就派上用场了。此函数使用字符串格式化参数,并返回一个字符串作为error的值。

让我们来试试Errorf函数,

package mainimport (    "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)}复制代码

在上面的程序中,第 10 行使用了Errorf, 打印导致错误的实际半径值,运行此程序将输出,

Area calculation failed, radius -20.00 is less than zero复制代码

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

也可以使用实现错误接口的结构类型作为error。这为我们提供了更多的灵活性。在我们的示例中,如果我们想要查看错误,唯一的方法是解析Area calculation failed, radius -20.00 is less than zero。这不是一种合适的方法,因为如果描述发生变化,我们的代码逻辑就得修改。

我们将使用前一个教程中所提到的“断言结构类型并从结构类型的字段中获取更多信息”方式,使用结构字段来提供errradius。我们将创建一个实现error接口的结构类型,并使用其字段提供有关的更多信息。

第一步是创建一个结构类型来表示error。类型的命名约定是Error结尾。所以我们将结构类型命名为areaError

type areaError struct {    err    string    radius float64}复制代码

上面的结构类型有一个字段radius,它存储了负责该error的半径值,而err字段则存储了实际的错误内容。

下一步是实现error接口。

func (e *areaError) Error() string {    return fmt.Sprintf("radius %0.2f: %s", e.radius, e.err)}复制代码

在上面的代码片段中,我们使用指针接收者* areaError实现错误接口的Error方法。该方法打印radiuserr描述。

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

package mainimport (    "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 rectangle1 %0.2f", area)}复制代码

在上面的程序中,第 17 行的circleArea用于计算圆的面积。此函数首先检查半径是否小于零,如果是,则使用该错误的半径和相应的错误内容描述去创建areaError,然后在第 19 行返回areaError的地址和错误内容。因此,我们提供了更多的error信息,在这个例子中,使用error结构的字段实现了自定义。

如果半径不是负数,则此函数计算并返回面积和nil

在第 26 行的main函数中,我们试图计算半径为-20 的圆面积。由于半径小于零,因此将返回错误。

我们在第 27 行检查err是否为nil,并在下一行中断言err* areaError类型。如果是* areaError类型,我们在 29 行使用err.radius获取造成errorradius,然后打印自定义错误内容并从程序返回。

输出,

Radius -20.00 is less than zero复制代码

现在让我们使用上一个教程中描述的第二个策略,并使用自定义错误类型的方法来提供有关error的更多信息。

使用结构类型的方法提供有关error的更多信息

在本节中,我们将编写一个计算矩形区域的程序。如果长度或宽度小于 0,该程序将打印错误。

第一步是创建一个表示error的结构。

type areaError struct {    err    string //error description    length float64 //length which caused the error    width  float64 //width which caused the error}复制代码

上面的错误结构类型包含错误描述字段err以及长度length和宽度width

现在我们已经定义好了error类型,让我们实现error接口并在类型上添加几个方法以提供有关的更多信息。

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方法返回错误的描述e.err。当length小于 0 时,lengthNegative方法返回true,而当width小于 0 时,widthNegative方法返回true。这两种方法提供了有关信息,在这种情况下,它们表示区域计算是否因为长度为负或宽度为负而失败。因此,我们使用error结构类型的方法来提供有关的更多信息。

下一步是实现面积计算功能。

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}复制代码

上面的rectArea函数检查长度或宽度是否小于 0,如果是,则返回 0 和error,否则返回矩形面积和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: 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)            }            return        }        fmt.Println(err)        return    }    fmt.Println("area of rect", area)}复制代码

main函数中,我们检查err是否为nil。 如果它不是nil,我们在下一行断言* areaError。然后使用lengthNegativewidthNegative方法,检查错误是否是因为长度为负或宽度为负。我们打印相应的error内容并从程序返回。因此,我们使用结构类型的方法来提供有关的更多信息。

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

最后贴出完整的程序供参考。

package mainimport "fmt"type areaError struct {    err    string  //error description    length float64 //length which caused the error    width  float64 //width which caused the error}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 += "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}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)            }            return        }    }    fmt.Println("area of rect", area)}复制代码

程序输出,

error: length -5.00 is less than zeroerror: width -9.00 is less than zero复制代码

我们已经看到了error处理教程中描述的三种方法中的两种的示例,以提供有关的更多信息。

第三种方式使用直接比较的方法比较简单。我会留下它作为练习,让您弄清楚如何使用此策略来提供有关我们的自定义error的更多信息。

转载于:https://juejin.im/post/5ca1ad13e51d4555c5453899

你可能感兴趣的文章
asp.net开源CMS推荐
查看>>
csharp skype send message in winform
查看>>
MMORPG 游戏服务器端设计--转载
查看>>
HDFS dfsclient写文件过程 源码分析
查看>>
ubuntu下安装libxml2
查看>>
nginx_lua_waf安装测试
查看>>
WinForm窗体缩放动画
查看>>
JQuery入门(2)
查看>>
linux文件描述符
查看>>
传值引用和调用引用的区别
查看>>
hyper-v 无线网连接
查看>>
Python3.7.1学习(六)RabbitMQ在Windows环境下的安装
查看>>
Windows下memcached的安装配置
查看>>
ubuntu: firefox+flashplay
查看>>
web.xml 中CharacterEncodingFilter类的学习
查看>>
贪吃蛇逻辑代码
查看>>
ASP.NET视频教程 手把手教你做企业论坛网站 视频教程
查看>>
[LeetCode] Meeting Rooms II
查看>>
从Swift学习iOS开发的路线指引
查看>>
Scribes:小型文本编辑器,支持远程编辑
查看>>