zoukankan      html  css  js  c++  java
  • golang错误处理

    1. 错误

    错误用内建的error类型来表示。

    type error interface {  
        Error() string
    }

    error 有了一个签名为 Error() string 的方法。所有实现该接口的类型都可以当作一个错误类型。Error()方法给出了错误的描述。

    package main
    import (
            "fmt"
            "os"
    )
    
    func main(){
            f, err := os.Open("/test.txt")
            if err != nil {
                    fmt.Println(err)
                    return
            }
            fmt.Println(f.Name(), "opened successfully")
    }
    output:
    open /test.txt: no such file or directory

    fmt.Println 在打印错误时,会在内部调用 Error() string 方法来得到该错误的描述。

    虽然获取了发生错误的文件路径,但是这种方法很不优雅。随着语言版本的更新,这条错误的描述随时都有可能变化,使我们程序出错

    1)     断言底层结构体类型,使用结构体字段获取更多信息

    通过阅读Open函数文档可知,返回的错误类型是*PathError。

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

    可通过断言*PathError类型,获取结构体详细字段内容:

    err是接口变量,err(*os.PathError)断言err的类型*os.PathError,从而获取接口的底层值,即*PathError。

        f, err := os.Open("/test.txt")
        if err, ok := err.(*os.PathError); ok {
            fmt.Println("File at path", err.Path, "failed to open")
            return
        }

    2)断言底层结构体类型,调用结构体方法获取更多信息

    3)直接比较

    filepath 包中的 ErrBadPattern 定义如下:

    var ErrBadPattern = errors.New("syntax error in pattern")

    直接比较错误类型

        files, error := filepath.Glob("[")
        if error != nil && error == filepath.ErrBadPattern {
            fmt.Println(error)
            return
        }

    2.自定义错误

    创建自定义错误最简单的方法是使用 errors 包中的 New 函数。

    package errors
    
    // New returns an error that formats as the given text.
    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
    }

    在函数中应用errors.New():

    func circleArea(radius float64) (float64, error) {  
        if radius < 0 {
            return 0, errors.New("Area calculation failed, radius is less than zero")
        }
        return math.Pi * radius * radius, nil
    }

    fmt.Errorf()打印错误信息

        if radius < 0 {
            return 0, fmt.Errorf("Area calculation failed, radius %0.2f is less than zero", radius)
        }

    使用结构体类型和字段提供错误的更多信息

    使用指针接收者 *areaError,实现了 error 接口的 Error() string 方法。

    type areaError struct {  
        err    string
        radius float64
    }
    
    func (e *areaError) Error() string {  
        return fmt.Sprintf("radius %0.2f: %s", e.radius, e.err)
    }
    
        if radius < 0 {
            return 0, &areaError{"radius is negative", radius}
        }

    使用结构体类型的方法来提供错误的更多信息

    type areaError struct {  
        err    string //error description
        length float64 //length which caused the error
        width  float64 //width which caused the error
    }
    func (e *areaError) Error() string {  
        return e.err
    }
    
    func (e *areaError) lengthNegative() bool {  
        return e.length < 0
    }
    
    func (e *areaError) widthNegative() bool {  
        return e.width < 0
    }
    func rectArea(length, width float64) (float64, error) {  
        err := ""
        if length < 0 {
            err += "length is less than zero"
        }
        if width < 0 {
            if err == "" {
                err = "width is less than zero"
            } else {
                err += ", width is less than zero"
            }
        }
        if err != "" {
            return 0, &areaError{err, length, width}
        }
        return length * width, nil
    }

    3.panic

    函数发生 panic 时,它会终止运行,在执行完所有的延迟函数后,程序控制返回到该函数的调用方。这样的过程会一直持续下去,直到当前协程的所有函数都返回退出,然后程序会打印出 panic 信息,接着打印出堆栈跟踪(Stack Trace),最后程序终止。

    需要注意的是,你应该尽可能地使用错误,而不是使用 panic 和 recover。只有当程序不能继续运行的时候,才应该使用 panic 和 recover 机制。

    panic 有两个合理的用例。

    • l  发生了一个不能恢复的错误,此时程序不能继续运行。 一个例子就是 web 服务器无法绑定所要求的端口。在这种情况下,就应该使用 panic,因为如果不能绑定端口,啥也做不了。
    • l  发生了一个编程上的错误。 假如我们有一个接收指针参数的方法,而其他人使用 nil 作为参数调用了它。在这种情况下,我们可以使用 panic,因为这是一个编程错误:用 nil 参数调用了一个只能接收合法指针的方法。
    func panic(interface{})

    panic(errors.New("error is ..."))

    recover 是一个内建函数,用于重新获得 panic 协程的控制。

    func recover() interface{}

    recover()返回的是panic()传入的interface,一般为error。

    只有在延迟函数的内部,调用 recover 才有用。在延迟函数内调用 recover,可以取到 panic 的错误信息,并且停止 panic 续发事件(Panicking Sequence),程序运行恢复正常。如果在延迟函数的外部调用 recover,就不能停止 panic 续发事件。

    只有在相同的 Go 协程中调用 recover 才管用。recover 不能恢复一个不同协程的 panic。

    参考:Go 系列教程 —— 32. panic 和 recover

  • 相关阅读:
    如何简化你的Vuex Store
    深入理解React中的setState
    vue双向绑定原理分析
    vue递归组件:树形控件
    Vue 3.0 的 Composition API 尝鲜
    React Native 与 Flutter 的跨平台之争
    javascript 变量赋值和 参数传递
    setTimeout 和 throttle 那些事儿
    一道面试题-变量声明提升~
    匹配文件扩展名两种方式
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/11128958.html
Copyright © 2011-2022 走看看