Go语言错误处理:Go Errors包的最佳实践

silverwq
2023-12-31 / 0 评论 / 65 阅读 / 正在检测是否收录...

errors. Is

用于判断该错误是否是某个类型,1.18 后,官方推荐使用 Is 来判断错误是否相等。

package main

import (
    "errors"
    "fmt"
)

var (
    ErrDivideByZero       = errors.New("divide by zero")
    ErrNegativeSquareRoot = errors.New("square root is negative")
)

func mathFunc(a, b int) error {
    if b == 0 {
        return ErrDivideByZero
    } else {
        return nil
    }
}

func main() {
    var a, b int
    err := mathFunc(a, b)
    if err != nil {
        // 此处等价于 err == ErrDivideByZero
        if errors.Is(err, ErrDivideByZero) {
            fmt.Println("除数为0异常")
        } else if errors.Is(err, ErrNegativeSquareRoot) {
            fmt.Println("对于负数开方异常")
        }
    }
}

和等号判断 err 是否相等相比,Is 判断还有个好处,就是如果是该错误的包装的话,Is 判断依据相等

package main

import (
    "errors"
    "fmt"
)

var (
    ErrDivideByZero       = errors.New("divide by zero")
    ErrNegativeSquareRoot = errors.New("square root is negative")
)

func mathFunc(a, b int) error {
    if b == 0 {
        // %w,可以对一个错误进行包装,应该是wrap的缩写
        return fmt.Errorf("mathFunc %w", ErrDivideByZero)
    } else {
        return nil
    }
}

func main() {
    var a, b int
    err := mathFunc(a, b)
    if err != nil {
        // fmt.Errorf("mathFunc %w", ErrDivideByZero),包装后,是不同的类型,不相等了
        if err == ErrDivideByZero {
            fmt.Println("除数为0异常,通过等号方式")
        }

        // 但是这个Is判断依旧相等
        if errors.Is(err, ErrDivideByZero) {
            fmt.Println("除数为0异常")
        } else if errors.Is(err, ErrNegativeSquareRoot) {
            fmt.Println("对于负数开方异常")
        }
    }
}

errors. As

这个方法除了可以判读类型是否是同一种,如果是的话,还会赋值初始化。

package main

import (
    "errors"
    "fmt"
)

type DivisionError struct {
    IntA int
    IntB int
    Msg  string
}

func (e DivisionError) Error() string {
    return e.Msg
}

type SquareError struct {
    IntA int
    IntB int
    Msg  string
}

func (e SquareError) Error() string {
    return e.Msg
}

func mathFunc(a, b int) error {
    if b == 0 {
        err := DivisionError{IntA: a, IntB: b, Msg: "除数为0"}
        return err
    } else {
        return nil
    }
}

func main() {
    var a, b int
    err := mathFunc(a, b)
    var de DivisionError
    var se SquareError
    if err != nil {
        // 判断err是否是DivisionError错误
        // 如果是的话,将err初始化到de,所以需要传指针
        if errors.As(err, &de) {
            // 所以这边可以直接取err的具体信息
            fmt.Printf("除数为0异常,a=%d,b=%d,msg=%s\n", de.IntA, de.IntB, de.Msg)
        } else if errors.Is(err, &se) {
            fmt.Printf("对负数开方异常,a=%d,b=%d,msg=%s\n", de.IntA, de.IntB, de.Msg)

        }
    }
}

同样,如果对错误进行包装,erros.As 判断依据成立

package main

import (
    "errors"
    "fmt"
)

type DivisionError struct {
    IntA int
    IntB int
    Msg  string
}

func (e DivisionError) Error() string {
    return e.Msg
}

type SquareError struct {
    IntA int
    IntB int
    Msg  string
}

func (e SquareError) Error() string {
    return e.Msg
}

func mathFunc(a, b int) error {
    if b == 0 {
        err := DivisionError{IntA: a, IntB: b, Msg: "除数为0"}
        // 对错误进行包装
        return fmt.Errorf("mathFunc %w", err)
    } else {
        return nil
    }
}

func main() {
    var a, b int
    err := mathFunc(a, b)
    var de DivisionError
    var se SquareError
    if err != nil {
        // 判断err是否是DivisionError错误
        // 如果是的话,将err初始化到de,所以需要传指针
        if errors.As(err, &de) {
            // 所以这边可以直接取err的具体信息
            fmt.Printf("除数为0异常,a=%d,b=%d,msg=%s\n", de.IntA, de.IntB, de.Msg)
        } else if errors.Is(err, &se) {
            fmt.Printf("对负数开方异常,a=%d,b=%d,msg=%s\n", de.IntA, de.IntB, de.Msg)

        }
    }
}
0

评论 (0)

取消