Golang学习之error篇

以一个打开系统文件为例,在error文件夹下有个hello.txt

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

import (
"fmt"
"os"
)

func main() {
file, err := os.Open("C:\\Users\\42012\\Desktop\\代码\\error\\hello.txt")
if err != nil {
fmt.Println("open file error")
}
fmt.Println(file, err)
fmt.Printf("Error的类型是:%T", err)
}

正常运行的结果是

1
2
&{0xc000072780} <nil>
Error的类型是:<nil>

当我们把hello.txt改成hello1.txt后,结果是

1
2
3
open file error
<nil> open C:\Users\42012\Desktop\代码\error\hello1.txt: The system cannot find the file specified.
Error的类型是:*os.PathError

控制台打印出了PathError路径错误,我们就可以根据error的类型和提示,快速定位代码中有问题的代码片段,并且加以修正。

自定义error

虽然golang有很多自带的error类型和提示,但是并不能完全覆盖所有的错误。

例如定义一个除法函数,当我们输入的被除数出现0时,整个程序就崩溃无法执行

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

import (
"fmt"
)

func DivisionForInt(dividend, divsor int) int {
return dividend / divsor
}

func main() {
fmt.Println(DivisionForInt(10, 5))
fmt.Println(DivisionForInt(10, 0))
fmt.Println(DivisionForInt(0, 100))

}

这时候运行程序得到的结果是

1
2
3
4
5
2
panic: runtime error: integer divide by zero

goroutine 1 [running]:
main.DivisionForInt(...)

可以看出在执行完第一个除法后,第二个除法的被除数为0,导致程序直接出现了panic崩溃,第三个除法也不会继续执行了。那么为了让程序更加健壮,我们需要对这个错误类型进行兼容处理,可以通过自定义error来解决。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"errors"
"fmt"
)

var errDivisionByZero = errors.New("被除数不能为0")

func DivisionForInt(dividend, divsor int) (int, error) {
if divsor == 0 {
return 0, errDivisionByZero
}
return dividend / divsor, nil
}

func main() {
fmt.Println(DivisionForInt(10, 5))
fmt.Println(DivisionForInt(10, 0))
fmt.Println(DivisionForInt(0, 100))

}

通过new得到一个自定义的error,在程序中对除数先进行判断,如果是0的话返回这个error给主程序

1
2
3
2 <nil>
0 被除数不能为0
0 <nil>

程序就不会发生崩溃,后面的除法也可以正常的运行。

另一种实现方式

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
package main

import (
"fmt"
)

type errDiv struct {
errStr string
}

func (e *errDiv) Error() string {
return e.errStr
}

func DivisionForInt2(dividend, divsor int) (int, error) {
if divsor == 0 {
return 0, &errDiv{
errStr: "除数不能为0哦",
}
}
return dividend / divsor, nil
}

func main() {
fmt.Println(DivisionForInt2(10, 5))
fmt.Println(DivisionForInt2(10, 0))
fmt.Println(DivisionForInt2(0, 100))
}

panic和recover