美文网首页GolangGo 语言学习专栏
『Go 内置库第一季:error』

『Go 内置库第一季:error』

作者: 谢小路 | 来源:发表于2018-11-08 23:25 被阅读25次
    VS CODE GOPHER.png

    大家好,我叫谢伟,是一名程序员。

    近期我会持续更新内置库的学习笔记,主要参考的是文档 godoc 和 内置库的源码

    本节的主题:error

    Go 中的错误处理和别的语言不一样,设计哲学也不一样,常有开发者埋怨 Go 语言中的错误处理。

    本节从内置库的 error 出发,结合内置库的常用的 错误处理手法,总结出适合项目的错误处理方式。

    大纲

    • 自己的常用的 error 错误处理方式
    • 内置库实现的 error
    • 总结

    自己的总结常用的 error 错误处理方式

    1. 创建 error 类型的值

    • errors.New()
    • fmt.Errorf()

    这两个方法即可实现。

    package main
    
    import (
        "errors"
        "fmt"
        "reflect"
    )
    
    func main() {
    
        recordError := errors.New("record not found")
        dbError := fmt.Errorf("%s", "db connet fail")
        fmt.Println(recordError, reflect.TypeOf(recordError))
        fmt.Println(dbError, reflect.TypeOf(dbError))
    
    }
    >>
    record not found *errors.errorString
    db connet fail *errors.errorString
    
    

    2. 自定义错误类型

    • 实现 error 接口
    type CodeError struct {
        Code    int
        Message string
    }
    
    func (c CodeError) Error() string {
        return fmt.Sprintf(" e.Code = %d, e.Message=%s", c.Code, c.Message)
    }
    
    func Result() error {
        var codeError CodeError
        codeError = CodeError{
            Code:    400,
            Message: "connect fail",
        }
        return codeError
    }
    
    func main(){
        
        var codeError CodeError
        var err error
        codeError = CodeError{
            Code:    404,
            Message: "http status code error",
        }
        err = codeError
        fmt.Println(err)
    }
    >>
    e.Code = 404, e.Message=http status code error
    

    自己定义的错误类型,只要实现了 error 接口即可。

    可以看下具体的 接口定义:

    type error interface {
        Error() string
    }
    
    
    • errors.New 的具体实现
    
    func New(text string) error {
        return &errorString{text}
    }
    
    // errorString is a trivial implementation of error.
    type errorString struct {
        s string
    }
    
    func (e *errorString) Error() string {
        return e.s
    }
    

    即 定义了 errorString 结构体, 绑定了 Error 方法

    • fmt.Errorf 的具体实现
    func Errorf(format string, a ...interface{}) error {
        return errors.New(Sprintf(format, a...))
    }
    

    即 fmt.Errorf 调用的也是 errors.New 方法。

    总结上文:

    1. 创建 error 存在两种方法
    2. 底层 是一个结构体实现了 error 接口
    3. 自定义的错误类型,实现 Error 方法即可

    内置库实现的 error

    错误很常见,是业务的一部分,那么内置的库在实现时也会遇到错误,看内置库是如何实现的 error

    1. strconv.Atoi

    func main(){
        
        number, err := strconv.Atoi("2992-121")
        fmt.Println(number,err)
    }
    >>
    0 strconv.Atoi: parsing "2992-121": invalid syntax
    

    具体的底层实现是:

    
    type NumError struct {
        Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat)
        Num  string // the input
        Err  error  // the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.)
    }
    
    func (e *NumError) Error() string {
        return "strconv." + e.Func + ": " + "parsing " + Quote(e.Num) + ": " + e.Err.Error()
    }
    

    定义各种错误类型:

    
    var ErrRange = errors.New("value out of range")
    var ErrSyntax = errors.New("invalid syntax")
    func syntaxError(fn, str string) *NumError {
        return &NumError{fn, str, ErrSyntax}
    }
    
    func rangeError(fn, str string) *NumError {
        return &NumError{fn, str, ErrRange}
    }
    
    func baseError(fn, str string, base int) *NumError {
        return &NumError{fn, str, errors.New("invalid base " + Itoa(base))}
    }
    
    func bitSizeError(fn, str string, bitSize int) *NumError {
        return &NumError{fn, str, errors.New("invalid bit size " + Itoa(bitSize))}
    }
    

    即:核心是定义了一个结构体,实现了 error 接口

    2. net/http

    func main(){
        
        response, err := http.Get("https://space.bilibili.com/10056291/#/")
        fmt.Println(response, err)
        
    }
    
    

    底层的错误类型是:

    
    type Error struct {
        Op  string
        URL string
        Err error
    }
    
    func (e *Error) Error() string { return e.Op + " " + e.URL + ": " + e.Err.Error() }
    
    

    即定义了一个结构体,实现的 error 接口。

    鉴于对内置库的底层的 错误类型的阅读,修改自己设置错误类型的方法:如下

    
    type ExampleError struct {
        Err     error
        Code    int
        Message string
    }
    
    func (e *ExampleError) Error() string {
        return fmt.Sprintf("e.Code = %d e.Err = %s e.Message = %s", e.Code, e.Err.Error(), e.Message)
    }
    
    func ExampleResult() error {
        return &ExampleError{
            Err:     errors.New("what the fucking life"),
            Code:    502,
            Message: "what the fucking life",
        }
    }
    

    总结

    • 创建 error 值存在两种方法
    • 自己定义的错误类型,只需实现 Error 方法,实现 error 接口即可

    其他:对错误的处理还有这些建议

    • 每个库,可以在库文件的开头声明常见的错误
    
    var ErrorIndexOut = errors.New("index out of range")
    var ErrorFuck = errors.New("fucking life")
    
    • 错误类型的变量可以带上 Err 或者 Error 标示
    • 建议统一处理错误类型,即,完整的项目在声明自己的库处理模块,而不是随意的在项目内创建 error

    <完>

    相关文章

      网友评论

        本文标题:『Go 内置库第一季:error』

        本文链接:https://www.haomeiwen.com/subject/mongxqtx.html