go定义的error 其实是一个interface
type error interface {
Err or() string
}
那么只要是实现这个接口的都可以当做一个error。譬如我们写一个除法函数:
main. go package main
import "fmt"
func Divide(a, b int) (int, error) {
if b == 0 {
return 0, fmt.Errorf("can't divide '%d' by zero ", a)
}
return a / b, nil
}
当被除数为0 的时候则返回一个错误。
更进一步,我们可以定义一个除0的错误 ErrDivideByZero。
package main
import (
"errors"
"fmt"
)
var ErrDivideByZero = errors.New("divide by zero")
func Divide(a, b int) (int, error) {
if b == 0 {
return 0, ErrDivideByZero //返回错误
}
return a / b, nil
}
func main() {
a, b := 10, 0
result, err := Divide(a, b)
if err != nil {
switch {//判断错误类型
case errors.Is(err, ErrDivideByZero):
fmt.Println("divide by zero error")
default:
fmt.Printf("unexpected division error: %s\n", err)
}
return
}
fmt.Printf("%d / %d = %d\n", a, b, result)
}
我们在函数调用的地方,就可以通过 errors.Is 判断是否是 ErrDivideByZero。
我们再更进一步,error 里面还可以携带更多的数据,譬如我们定义 DivisionError 里面包含了除数、被除数以及错误信息。并且实现 Error 接口,如下:
type DivisionError struct {
IntA int
IntB int
Msg string
}
func (e *DivisionError) Error() string {
return e.Msg
}
后续使用的时候,我们就可以读取error里面的信息,然后进行响应处理了。
func Divide(a, b int) (int, error) {
if b == 0 {
return 0, &DivisionError{
Msg: fmt.Sprintf("cannot divide '%d' by zero", a),
IntA: a, IntB: b,
}
}
return a / b, nil
}
func main() {
a, b := 10, 0
result, err := Divide(a, b)
if err != nil {
var divErr *DivisionError
switch {
case errors.As(err, &divErr):
fmt.Printf("%d / %d is not mathematically valid: %s\n",
divErr.IntA, divErr.IntB, divErr.Error())
default:
fmt.Printf("unexpected division error: %s\n", err)
}
return
}
fmt.Printf("%d / %d = %d\n", a, b, result)
}
上面判断error 类型的时候用的是 errors.Is ,这里 error 类型转化的时候用的是 errors.As 大家不要弄混了。