首页 > 其他分享 >go教程10

go教程10

时间:2024-01-23 10:47:18浏览次数:31  
标签:10 教程 return err 错误 width length radius go

1.     自定义错误

上一教程里,我们学习了 Go 中的错误是如何表示的,并学习了如何处理标准库里的错误。我们还学习了从标准库的错误中提取更多的信息。

在本教程中,我们会学习如何创建我们自己的自定义错误,并在我们创建的函数和包中使用它。我们会使用与标准库中相同的技术,来提供自定义错误的更多细节信息。

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

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

在使用 New 函数 创建自定义错误之前,我们先来看看 New 是如何实现的。如下所示,是 errors  中的 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
}

New 函数的实现很简单。errorString 是一个结构体类型,只有一个字符串字段 s。第 14 行使用了 errorString 指针接受者(Pointer Receiver),来实现 error 接口的 Error() string 方法

第 5 行的 New 函数有一个字符串参数,通过这个参数创建了 errorString 类型的变量,并返回了它的地址。于是它就创建并返回了一个新的错误。

现在我们已经知道了 New 函数是如何工作的,我们开始在程序里使用 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)
}

glayground 上运行

在上面的程序中,我们检查半径是否小于零(第 10 行)。如果半径小于零,我们会返回等于 0 的面积,以及相应的错误信息。如果半径大于零,则会计算出面积,并返回值为 nil 的错误(第 13 行)。

在 main 函数里,我们在第 19 行检查错误是否等于 nil。如果不是 nil,我们会打印出错误并返回,否则我们会打印出圆的面积。

在我们的程序中,半径小于零,因此打印出:

Area calculation failed, radius is less than zero

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

上面的程序效果不错,但是如果我们能够打印出当前圆的半径,那就更好了。这就要用到 fmt 包中的 Errorf 函数了。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)
}

playground 上运行

在上面的程序中,我们使用 Errorf(第 10 行)打印了发生错误的半径。程序运行后会输出:

Area calculation failed, radius -20.00 is less than zero

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

错误还可以用实现了 error 接口的结构体来表示。这种方式可以更加灵活地处理错误。在上面例子中,如果我们希望访问引发错误的半径,现在唯一的方法就是解析错误的描述信息 Area calculation failed, radius -20.00 is less than zero。这样做不太好,因为一旦描述信息发生变化,程序就会出错。

我们会使用标准库里采用的方法,在上一教程中“断言底层结构体类型,使用结构体字段获取更多信息”这一节,我们讲解了这一方法,可以使用结构体字段来访问引发错误的半径。我们会创建一个实现 error 接口的结构体类型,并使用它的字段来提供关于错误的更多信息。

第一步就是创建一个表示错误的结构体类型。错误类型的命名约定是名称以 Error 结尾。因此我们不妨把结构体类型命名为 areaError

type areaError struct {  
    err    string
    radius float64
}

上面的结构体类型有一个 radius 字段,它存储了与错误有关的半径,而 err 字段存储了实际的错误信息。

下一步是实现 error 接口。

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

在上面的代码中,我们使用指针接收者 *areaError,实现了 error 接口的 Error() string 方法。该方法打印出半径和关于错误的描述。

现在我们来编写 main 函数和 circleArea 函数来完成整个程序。

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 rectangle1 %0.2f", area)
}

playground 上运行

在上面的程序中,circleArea(第 17 行)用于计算圆的面积。该函数首先检查半径是否小于零,如果小于零,它会通过错误半径和对应错误信息,创建一个 areaError 类型的值,然后返回 areaError 值的地址,与此同时 area 等于 0(第 19 行)。于是我们提供了更多的错误信息(即导致错误的半径),我们使用了自定义错误的结构体字段来定义它

如果半径是非负数,该函数会在第 21 行计算并返回面积,同时错误值为 nil

在 main 函数的 26 行,我们试图计算半径为 -20 的圆的面积。由于半径小于零,因此会导致一个错误。

我们在第 27 行检查了错误是否为 nil,并在下一行断言了 *areaError 类型。如果错误是 *areaError 类型,我们就可以用 err.radius 来获取错误的半径(第 29 行),打印出自定义错误的消息,最后程序返回退出

如果断言错误,我们就在第 32 行打印该错误,并返回。如果没有发生错误,在第 35 行会打印出面积。

该程序会输出:

Radius -20.00 is less than zero

下面我们来使用上一教程提到的第二种方法,使用自定义错误类型的方法来提供错误的更多信息。

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

在本节里,我们会编写一个计算矩形面积的程序。如果长或宽小于零,程序就会打印出错误。

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

type areaError struct {  
    err    string //error description
    length float64 //length which caused the error
    width  float64 //width which caused the 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() string 方法中返回了关于错误的描述。当 length 小于零时,lengthNegative() bool 方法返回 true,而当 width 小于零时,widthNegative() bool 方法返回 true这两个方法都提供了关于错误的更多信息,在这里,它提示我们计算面积失败的原因(长度为负数或者宽度为负数)。于是我们就有了两个错误类型结构体的方法,来提供更多的错误信息

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

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 函数检查了长或宽是否小于零,如果小于零,rectArea 会返回一个错误信息,否则 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: 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 程序中,我们检查了错误是否为 nil(第 4 行)。如果错误值不是 nil,我们会在下一行断言 *areaError 类型。然后,我们使用 lengthNegative() 和 widthNegative() 方法,检查错误的原因是长度小于零还是宽度小于零。这样我们就使用了错误结构体类型的方法,来提供更多的错误信息。

如果没有错误发生,就会打印矩形的面积。

下面是整个程序的代码供你参考。

package main
 
import "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(err)
        return
    }
    fmt.Println("area of rect", area)
}

playground 上运行

该程序会打印输出:

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

在上一教程错误处理中,我们介绍了三种提供更多错误信息的方法,现在我们已经看了其中两个示例。

第三种方法使用的是直接比较,比较简单。我留给读者作为练习,你们可以试着使用这种方法来给出自定义错误的更多信息。

本教程到此结束。

简单概括一下本教程讨论的内容:

  • 使用 New 函数创建自定义错误
  • 使用 Error 添加更多错误信息
  • 使用结构体类型和字段,提供更多错误信息
  • 使用结构体类型和方法,提供更多错误信息

祝你愉快。

 

标签:10,教程,return,err,错误,width,length,radius,go
From: https://www.cnblogs.com/gongxianjin/p/17981814

相关文章

  • go教程9
    什么是defer?defer 语句的用途是:含有 defer 语句的函数,会在该函数将要返回之前,调用另一个函数。这个定义可能看起来很复杂,我们通过一个示例就很容易明白了。示例packagemain import(     "fmt") funcfinished(){     fmt.Println("Finishedfindi......
  • go教程11
    1.    Panic和recover什么是panic?在Go语言中,程序中一般是使用错误来处理异常情况。对于程序中出现的大部分异常情况,错误就已经够用了。但在有些情况,当程序发生异常时,无法继续运行。在这种情况下,我们会使用 panic 来终止程序。当函数发生panic时,它会终止运行,在执行......
  • go教程12
    1.    读取文件文件读取是所有编程语言中最常见的操作之一。本教程我们会学习如何使用Go读取文件。本教程分为如下小节。将整个文件读取到内存使用绝对文件路径使用命令行标记来传递文件路径将文件绑定在二进制文件中分块读取文件逐行读取文件将整个文件读取......
  • ABS210-ASEMI智能LED灯具专用ABS210
    编辑:llABS210-ASEMI智能LED灯具专用ABS210型号:ABS210品牌:ASEMI封装:ABS-4最大重复峰值反向电压:1000V最大正向平均整流电流(Vdss):2A功率(Pd):50W芯片个数:4引脚数量:4类型:贴片、方桥正向浪涌电流:60A正向电压:1.10V最大输出电压(RMS):700V封装尺寸:如图工作温度:-55°C~150°C......
  • go教程
    这是我们 Golang系列教程的第一个教程。1.    GO介绍与安装Golang是什么     Go亦称为Golang(译注:按照RobPike说法,语言叫做Go,Golang只是官方网站的网址),是由谷歌开发的一个开源的编译型的静态语言。     Golang的主要关注点是使得高可用性和可扩展......
  • 使用Go进行HTTP客户端认证
    在Go语言中,HTTP客户端认证可以通过net/http包来实现。下面是一个简单的示例,展示如何使用Go进行HTTP客户端认证。首先,确保你已经安装了Go语言环境,并设置好了相关的环境变量。Go语言中的HTTP客户端认证主要涉及到设置请求头中的认证信息。以下是一个简单的示例代码,展示了如何使用Go发......
  • 在Go中处理HTTP重定向
    在Go语言中处理HTTP重定向是一个常见的任务,特别是在开发Web应用程序或与Web服务进行交互时。HTTP重定向是一种服务器端的行为,它告诉客户端请求的资源已移动到新的位置,并提供了新的位置信息。Go语言的net/http包提供了处理HTTP请求和响应的工具,包括重定向的处理。以下是一个示例,展示......
  • 使用Go编写HTTP中间件
    在Go语言中,HTTP中间件是一种处理HTTP请求和响应的函数,它可以拦截到请求并对其进行处理,然后再将请求传递给下一个中间件或目标处理程序。HTTP中间件在Web应用程序中非常常见,它提供了一种机制来执行各种任务,例如身份验证、授权、日志记录和错误处理等。下面是一个使用Go编写HTTP中间......
  • 使用Go进行HTTP性能优化
    Go语言,也被称为Golang,是一种高效且强大的编程语言,特别适合构建高性能的Web应用程序。在处理HTTP请求时,通过一些优化技巧,可以显著提高应用程序的性能。以下是一些使用Go进行HTTP性能优化的方法:1. 并发处理:Go语言内置的并发原语,如goroutine和channel,使得并发编程变得简单而高效。你......
  • MacOSX系统jcefmaven用JDK17启动教程
    拉取代码,gitclonehttps://github.com/jcefmaven/jcefmaven.git导入IDE,我用的是IntelliJIDEA2023.3,如果用其他的就正常导入Maven项目就行了。Maven构建一下运行Main方法,运行me.friwi.jcefsampleapp.MainFrame#main方法。修改一下这里的地址,默认是谷歌,可以改成百度或......