go 错误 异常

自定义错误

 Go语言中  错误使用内建的 error 类型表示, error类型是一个接口类型:定义如下:

 error 有一个 Error() 的方法‘所有实现该接口的类型 都可以当做一个错误的类型;Error()方法输入具体错误描述,在打印错误时 可以调用 Error() 来输出错误

type error struct {
	Error() string
}

对于简单的数据类型,一个 println 就可以了,

但是对于复杂类型 我们可以通过继承接口的方式 灵活的方式进行:

例如一个计算面积的函数:需要判断输入是否合法:比如输入负数则报错!

  

方式1:

//计算面积
//输入两个数 返回 面积和错误
func area(a, b int) (int, error) {
	if a < 0 || b < 0 {
		//第一种
		//return 0, errors.New("计算长度 不能为负数")
		//第二种
		return 0, fmt.Errorf("计算长度 不能为负数; 长度%d,宽度%d 不能小于0", a, b)
		//return 0, &areaError{"计算长度 不能为负数", a, b}
	}
	return a * b, nil
}


//调用:

a := 20
b := -56

r, err := area(a, b)
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println("area:", r)

输入:
计算长度 不能为负数

计算长度 不能为负数; 长度20,宽度-56 不能小于0

  

方式2:

//定义错误结构体
type areaError struct {
	err    string //错误描述
	length int    //宽度
	width  int    //长度
}
//实现一个接口
func (e *areaError) Error() string {
	//return fmt.Sprintf("length %d, width %d", e.length, e.width)
	return e.err
}


//求面积函数
func area(a, b int) (int, error) {
	if a < 0 || b < 0 {
		return 0, &areaError{"计算长度 不能为负数", a, b}
	}
	return a * b, nil
}


//调用:
a := 20
b := -56

r, err := area(a, b)
//写法1
if err != nil {
	if err, ok := err.(*areaError); ok {
		fmt.Printf("length %d or width %d is less than zero\n", err.length, err.width)
		fmt.Println(err)
		return
	}
	fmt.Println(err)
	return
}
fmt.Println("area:", r)


输出:
length 20 or width -56 is less than zero
计算长度 不能为负数

方式3:

//定义结构体和 函数
type areaError struct {
	err    string //错误描述
	length int    //宽度
	width  int    //长度
}

func (e *areaError) Error() string {
	//return fmt.Sprintf("length %d, width %d", e.length, e.width)
	return e.err
}

func (e *areaError) widthNegative() bool {
	return e.width < 0
}

func (e *areaError) lengthNegative() bool {
	return e.length < 0
}


//面积函数的定义
func area(length, width int) (int, error) {
	err := ""
	if length < 0 {
		err += "length is negative"
	}
	if width < 0 {
		err += "width is negative"
	}
	if err != "" {
		return 0, &areaError{err: err, length: length, width: width}
	}
	return length * width, nil
}



//调用:
a := 20
b := -56

r, err := area(a, b)
if err != nil {
	if err, ok := err.(*areaError); ok {
		if err.lengthNegative() {
			fmt.Println("Length is error :", err.length)
		}
		if err.widthNegative() {
			fmt.Println("width is error :", err.width)
		}
		fmt.Printf("length:%d, width:%d\n", err.length, err.width)
		return
	}
	fmt.Println(err)
}
fmt.Println("area:", r)


//输出:
width is error : -56
length:20, width:-56

异常

异常和错误 是两个不同的概念,容易混淆:

  • 错误是指:在有可能出现问题的地方,出现了问题
  • 异常是指:在不应该出现问题的地方,出现了问题

 

go 中的处理异常的主要有两种

  1. panic会导致程序会终止,在编写程序的时候 尽量使用错误; 只有在程序不能继续进行下去的时候在使用  panic,在发生 panic 的时候使用 recover 防止程序终止

    // 会导致程序会终止,在编写程序的时候 尽量使用 错误; 只有在程序不能继续进行下去的时候在使用: panic, recover
    func myTest() {
    	defer fmt.Println("myTest defer")
    	panic("myTest panic")
    }
    
    
    func main() {
    	defer fmt.Println("main defer")
    	myTest()
    	fmt.Println("main ...")
    }
    
    
    输出:带错误码的异常中断,并且程序没有执行完整;   没有打印 fmt.Println("main ...")
    
    myTest defer
    main defer
    panic: myTest panic
    
    goroutine 1 [running]:
    main.myTest()
            D:/awesomeProject/grammar/chapter08/main.go:18 +0x73
    main.main()
            D:/awesomeProject/grammar/chapter08/main.go:7 +0x70
    
    Process finished with the exit code 2
    
    

  2. recover recover 类似与其他语音 try catch但是它只有在 相同的协程中才能 recover到异常,继续执行代码 不至于奔溃

    // 在发生 panic 的时候, recover 防止程序终止
    // recover 类似与  try catch 只有在相同的协程中才能 recover到异常,继续执行代码 不至于奔溃
    func outOfArray(x int) {
    	defer func() {
    		if err := recover(); err != nil {
    			fmt.Println(err)
    		}
    	}()
    
    	var array [5]int
    	array[x] = 1
    }
    
    
    
    func main() {
    	outOfArray(6)
    	fmt.Println("main ...")
    
    }
    
    输出: 带错误输出,并且程序继续往下执行 (执行完整) 输出 fmt.Println("main ...")
    
    runtime error: index out of range [6] with length 5
    main ...
    
    Process finished with the exit code 0
    

你可能感兴趣的:(go,语法基础特性,golang)