28、错误error

发布时间 2023-10-07 20:59:23作者: 我也有梦想呀

1、是什么?

在实际的项目中,我们希望通过程序的错误信息快速定位问题,但是又不喜欢错误处理;代码就会很冗余又啰嗦。Go语言没有提供类似Java、C#语言中的try...catch异常处理方法,而是通过函数返回值逐层往上抛。这种设计,鼓励工程师在代码中显示的检查错误,而非忽略错误,好处就是避免漏掉应该处理的错误。但是代码带来的弊端就是,让代码啰嗦了。

错误是指在可能出现问题的地方出现了问题。比如打开一个文件时失败,这种情况再人们的意料之中

而异常指的是不应该在出现问题的地方出现了问题。比如NPE,这种情况再人们的意料之外。错误是业务流程的一部分,而异常不是。

Go语言中错误也是一种类型,错误用内置的error表示,就像其他类型如:int、float64.错误值可以存储在变量中,从函数中返回,等等...

2、错误演示

创建错误的方式:
1、errors.New()
2、fmt.Errorf()

/**
 * @author ly (个人博客:https://www.cnblogs.com/ybbit)
 * @date 2023/9/30  23:43
 * @tags 喜欢就去努力的争取
 */
package main

import (
	"errors"
	"fmt"
)

func main() {

	/*
		创建错误的方式:
			1、errors.New()
			2、fmt.Errorf()
	*/

	err1 := errors.New("我创建的错误")
	fmt.Println(err1)
	fmt.Printf("%T\n", err1)

	err2 := fmt.Errorf("错误信息", 500)
	fmt.Println(err2)
	fmt.Printf("%T \n", err2)

	err3 := checkAge(-10)
	if err3 != nil {
		fmt.Println(err3)
		return
	}
	fmt.Println("程序...go...on...")
}

func checkAge(age int) error {
	if age < 0 {
		// return errors.New("年龄不合法")
		return fmt.Errorf("您给定的年龄是:%d,不合法", age)
	}
	fmt.Println("年龄为:", age)
	return nil
}

3、错误类型表示

/**
 * @author ly (个人博客:https://www.cnblogs.com/ybbit)
 * @date 2023/10/1  11:16
 * @tags 喜欢就去努力的争取
 */
package main

import (
	"fmt"
	"net"
	"os"
	"path/filepath"
)

func main() {
	f, err := os.Open("test.txt")
	if err != nil {
		fmt.Println("err", err)
		if ins, ok := err.(*os.PathError); ok {
			fmt.Println("1.Op", ins.Op)
			fmt.Println("2.Path", ins.Path)
			fmt.Println("3.Err", ins.Err)
		}
		return
	}
	fmt.Println("文件打开成功:", f.Name())

	addr, err := net.LookupHost("www.baidu999999.com")
	fmt.Println(err)
	if ins, ok := err.(*net.DNSError); ok {
		if ins.Timeout() {
			fmt.Println("操作超时...")
		} else if ins.Temporary() {
			fmt.Println("临时性错误...")
		} else {
			fmt.Println("出错了")
		}
	}
	fmt.Println(addr)

	// 匹配指定错误
	files, err := filepath.Glob("[")
	if err != nil && err == filepath.ErrBadPattern {
		fmt.Println(err)
		return
	}
	fmt.Println("files:", files)
}

注意:不要忽略错误,也就是不要使用_去忽略他

4、自定义error

/**
 * @author ly (个人博客:https://www.cnblogs.com/ybbit)
 * @date 2023/10/1  11:37
 * @tags 喜欢就去努力的争取
 */
package main

import (
	"fmt"
	"math"
)

func main() {
	// 自定义错误
	radius := -3.0
	area, err := circleArea(radius)
	if err != nil {
		fmt.Println(err)
		if err, ok := err.(*areaError); ok {
			fmt.Printf("半径为:%.2f \n", err.radius)
		}
		return
	}
	fmt.Println("圆形的面积为:", area)
}

type areaError struct {
	msg    string
	code   int
	radius float64
}

func (e *areaError) Error() string {
	return fmt.Sprintf("error:半径,%.2f,%s,%d", e.radius, e.msg, e.code)
}

func circleArea(redius float64) (float64, error) {
	if redius < 0 {
		return 0, &areaError{"半径不合法", 500, redius}
	}
	return math.Pi * redius * redius, nil
}

/**
 * @author ly (个人博客:https://www.cnblogs.com/ybbit)
 * @date 2023/10/7  20:26
 * @tags 喜欢就去努力的争取
 */
package main

import "fmt"

func main() {

	length, width := 5.7, -8.2
	area, err := rectArea(length, width)
	if err != nil {
		fmt.Println(err)
		if err, ok := err.(*areaError); ok {
			if err.lengthNegative() {
				fmt.Printf("长度小于0,length: %.2f \n", length)
			}
			if err.widthNegative() {
				fmt.Printf("宽度小于0,wigth: %.2f \n", length)
			}
		}
		return
	}
	fmt.Println("面积S为:", area)
}

type areaError struct {
	msg    string
	length float64
	width  float64
}

func (e *areaError) Error() string {
	return e.msg
}

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) {
	msg := ""
	if length < 0 {
		msg = "长度小于0"
	}
	if width < 0 {
		if msg == "" {
			msg = "宽度小于0"
		} else {
			msg += ",宽度也小于0"
		}
	}
	if msg != "" {
		return 0.0, &areaError{msg, length, width}
	}
	return length * width, nil
}