go错误机制

Go 没有像 Java 和 .NET 那样的 try/catch 异常机制:不能执行抛异常操作。但是有一套 defer-panic-and-recover 机制。

go 的返回支持多个参数,一般由异常的信息的时候,将异常也返回给调用者,由调用者判断是否有异常需要处理。

生成异常并处理

errors 类中定义了多个生成错误的相关方法。

errors.new() 创建一个错误,用于向调用者返回error 信息
errors.Is() 判断是否是指定的错误类型
errors.As() As 方法的作用是在第一个参数 err 的调用链中寻找和第二个参数 target 类型相同的的错误,并把找到的第一个 err 的值赋给 target ,然后返回 true;如果没有找到则返回 false。
errors.Unwrap(err error) 解开内部的错误类型,一般可能会通过聚合了内部类型的自定义错误类型来返回

调用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

func devide(a int,b int) (float64,error) {
if(b <= 0){
return 0,errors.New("被除数不允许小于等于0")
}
return float64(a) / float64(b),nil
}

func TestErr(t *testing.T) {
ret,err := devide(10,0)
if(err != nil){
t.Error(err)
return
}
t.Logf("得到的结果是 %f",ret)
}

通过自定义错误类型来判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

var RangeError error = errors.New("数值范围错误,必须大于等于0")

var DevideZeroError error = errors.New("被除数不能等于0")


func devide(a int,b int) (float64,error) {
if(a <0 || b < 0){
return 0,RangeError
}
if(b == 0){
return 0,DevideZeroError
}
return float64(a) / float64(b),nil
}

func TestErr(t *testing.T) {
ret,err := devide(-3,-1)
if(err != nil){
if(errors.Is(err,DevideZeroError)){
fmt.Println("除数为0 了")
}
if(errors.Is(err,RangeError)){
fmt.Println("不能小于0了")
}
return
}
t.Logf("得到的结果是 %f",ret)
}


panic

panic 用于处理一个不能恢复和处理的错误。

1
2
3
4
5
6
7
func TestErr2(t *testing.T) {
defer func() {
t.Log("最终的结果执行。。。。")
}()
panic(errors.New("错误信息"))
t.Log("结束===>")
}

panic 不会影响 defer的执行

recover 恢复错误

recover 用于将程序从panic错误中恢复。
recover 只能用在 defer 修饰的函数中。

recover 是在当前的函数结束的时候对此函数能够处理的panic进行恢复,但是panic 开始位置到函数末尾的代码将不会执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func errorFunc()  {
panic("有错误了")
}



func method() {
fmt.Println("method start ")
defer func() {
if err := recover();err != nil {
fmt.Println("===>error")
fmt.Printf("Panicing %s\r\n", err)
}
}()
errorFunc()
fmt.Println("method end ")
}

func TestRecover(t *testing.T) {
method()
fmt.Println("test==end")
}