在本教程中,我们将讨论如何自定义错误。之后,我们将使用标准库提供的方法,去让错误拥有更多的信息。
New
函数 自定义错误通过 errors
包 的 New
函数,我们可以自定义错误,这是最简单的方式。
在自定义错误之前,我们先看看 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
字段。通过指针接收器,errorString
结构 实现了 error
接口。
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)
}
在上面程序的第 10
行,我们判断半径是否小于 0
。
0
,我们返回 0
面积、以及相应的错误。0
,我们返回 相应的面积、以及 nil
错误。在 main
函数中,我们判断错误是否为 nil
。
nil
,我们就输出相应的错误。nil
,我们就输出算得的面积。在上面的程序中,由于半径小于 0
,所以程序输出为:
Area calculation failed, radius is less than zero
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)
}
在上面程序的第 10
行,我们使用 Errorf
函数,将半径格式化进错误内部。
运行程序,程序输出如下:
Area calculation failed, radius -20.00 is less than zero
在上面的程序中,如果想访问 引发错误的半径,我们可以解析错误描述信息: Area calculation failed, radius -20.00 is less than zero
。但是,这种方法不够优美,而且在错误描述信息改变时,我们的代码也将无法运行。
那如何实现这样的目的呢?我们可以将半径封装进结构体,并让该结构体实现 error
接口。通过这样方式,我们能实现更加灵活的错误处理。
接下来,我们来创建一个代表错误的结构体。
type areaError struct {
err string
radius float64
}
一般来说,错误类型命名的后缀一定要是
Error
。因此,我们将该结构体命名为areaError
。
在上面的结构体中,err
字段 存储了 错误的描述信息,而 radius
字段 存储了 引发错误的半径。
接下来,我们让该结构体实现 error
接口。
func (e *areaError) Error() string {
return fmt.Sprintf("radius %0.2f: %s", e.radius, e.err)
}
添加了 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)
}
circleArea
函数 能计算圆的面积。这个函数会先判断半径:
0
,它将 引发错误的半径、相应的错误描述信息 封装进 areaError
结构后,返回 0
面积、areaError
结构的地址。0
,则直接返回 圆的面积、nil
错误。在 main
函数 中,我们试着求取 半径为-20
的圆 的面积。因为半径小于 0
,所以 circleArea
函数 将返回错误。
在第 27
行,我们对 circleArea
函数返回的错误 进行判断:
nil
,我们就输出面积。nil
,我们将错误断言为 *areaError
类型,
err.radius
,我们就能获取到错误内部的 radius
。程序输出如下:
Radius -20.00 is less than zero
这一节,我们将写一个程序,这个程序功能为:计算矩形的面积,矩形长度或宽度为 0
时返回错误。
先创建一个代表错误的结构体:
type areaError struct {
err string //error description
length float64 //length which caused the error
width float64 //width which caused the error
}
areaError
结构体 包含了 错误的描述信息err
、矩形长度length
、矩形宽度width
。
接下来,我们让 areaError
结构 实现 error
接口,并为其添加 lengthNegative
、widthNagative
方法,这 2
个方法用以提供更多的错误信息。
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
方法 会返回错误的描述信息。lengthNegative
、widthNegative
方法 会返回布尔值,2
个方法的布尔值分别表示:长度是否小于 0
、宽度是否小于 0
。
之所以 lengthNegative
、widthNegative
方法 能提供更多的错误信息,是因为通过调用这 2
个方法,我们就能知道:错误到底是因长度小于 0
引起的,还是因宽度小于 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
}
rectArea
函数 会先对长度、宽度进行判断:
0
,则返回 0
面积、相应错误。0
,则返回 矩形面积、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
函数中,我们对 rectArea
函数返回的错误 进行判断:
nil
,此时表示没有错误,程序直接输出矩形面积。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("area of rect", area)
}
运行程序,输出如下:
error: length -5.00 is less than zero
error: width -9.00 is less than zero
在 Go语言 错误处理 这一节中,我们描述了 3
种 从错误中获取更多信息 的方法,但在这一节,我只是写了 2
种 为错误添加更多信息 的方法。
为错误添加更多信息的第 3
个方法是 直接比较。这个方法很简单,我将它留作练习。你们可以想想,怎么使用这个方法,为错误添加更多信息。
这就是全部内容了~
祝你长高高~
优质内容来之不易,您可以通过该 链接 为我捐赠。
感谢原作者的优质内容。
欢迎指出文中的任何错误。