• Don't just check errors, handle them gracefully


    原文链接

    https://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-gracefully

    翻译总结下Dave主要分享的几个观点:

    避免前哨式的错误处理,因为一些错误处理而引入大量的包,比如下main这种,如果我们处理一个io.EOF,还要引入io包,当然我认为这是蛮常见的处理,但是之前本身并没有注意到这点的坏处,其实也很简单,过度的依赖关系。

    if err == ErrSomething { … }

    避免错误类型,还是那个问题,首先你的错误类型必须是公开的,如果你的项目需要有特定的错误类型,那么你将无限依赖它,当然这并非不可以,还是过度的依赖会让你的API脆弱。所以建议还是避免错误类型,或者至少避免使它们成为公共API的一部分。

    type MyError struct {
            Msg string
            File string
            Line int
    }
    
    func (e *MyError) Error() string { 
            return fmt.Sprintf("%s:%d: %s”, e.File, e.Line, e.Msg)
    }
    
    return &MyError{"Something happened", “server.go", 42}
    err := something()
    switch err := err.(type) {
    case nil:
            // call succeeded, nothing to do
    case *MyError:
            fmt.Println(“error occurred on line:”, err.Line)
    default:
    // unknown error
    }

    不透明的错误,这或许是最常见的一种策略,但是也并不是完美的,还是需要一些后续的处理。

    import “github.com/quux/bar”
    
    func fn() error {
            x, err := bar.Foo()
            if err != nil {
                    return err
            }
            // use x
    }

    断言行为而不是类型

    type temporary interface {
        Temporary() bool
    }
    
    func IsTemporary(err error) bool {
        te, ok := err.(temporary)
        return ok && te.Temporary()
    }

    这个例子看着可能蛮复杂,分析一下就是,首先这个错误是实现了temporary接口,如果是这种错误证明它存在一种Temporary的行为,我们可以根据这个isTemporary来进行重试操作。这段代码还是看的很舒服的,我也是第一次知道这种思路。

    重点来了,检查完了,还要处理,这里Dave主要讲了几点:

    首先是借助github.com/pkg/errors

    1.添加上下文

    func ReadFile(path string) ([]byte, error) {
        f, err := os.Open(path)
        if err != nil {
            return nil, errors.Wrap(err, "open failed")
        }
        defer f.Close()
    
        buf, err := ioutil.ReadAll(f)
        if err != nil {
            return nil, errors.Wrap(err, "read failed")
        }
    
        return buf, nil
    }
    
    func ReadConfig() ([]byte, error) {
        home := os.Getenv("HOME")
        config, err := ReadFile(filepath.Join(home, ".settings.xml"))
        return config, errors.Wrap(err, "could not read config")
    }
    
    
    func main() {
        _, err := ReadConfig()
        if err != nil {
            fmt.Println(err)
            os.Exit(1)
        }
    }

    2.仅处理一次错误

    func Write(w io.Writer, buf []byte) error {
            _, err := w.Write(buf)
            if err != nil {
                    // annotated error goes to log file
                    log.Println("unable to write:", err)
     
                    // unannotated error returned to caller
                    return err
            }
            return nil
    }
    
    
    func Write(w io.Writer, buf []byte) error {
        _, err := w.Write(buf)
        return errors.Wrap(err, "write failed")
    }

    前者的Write方法加了一个log,又返回一个err,这样的结果就是不断的返回一直到顶级,看log是一堆err实际上有效的只有一个可能。

    end

    一个没有高级趣味的人。 email:hushui502@gmail.com
  • 相关阅读:
    python限定方法参数类型、返回值类型、变量类型等
    双拼自然码
    关于将汉语拼音字母“ü”改成“v”的设想和建议
    数据库转模型图
    python中的捕获异常、异常跟踪
    内部教师爆料:某些民办学校真正的内幕
    炸薯条
    IntelliJ IDEA添加JavaDOC注释 方法 快捷键
    java获取当前路径的方法
    java获取全部子类或接口的全部实现
  • 原文地址:https://www.cnblogs.com/CherryTab/p/12797017.html
Copyright © 2020-2023  润新知