如何减少重复err

曾看到一篇blog,说他们一个项目最后扫盲出几千个

if err != nil

没有对比就没有伤害

Golang的主程都是工程界的高手,而且还有一堆geek社区,自然有办法让err,不那么难看。几个示例

参考Rob Pike的一篇blog

https://blog.golang.org/errors-are-values

io.Writer 例子:

_, err = fd.Write(p0[a:b])
if err != nil {
    return err
}
_, err = fd.Write(p1[c:d])
if err != nil {
    return err
}
_, err = fd.Write(p2[e:f])
if err != nil {
    return err
}
// and so on

这看起来太糟糕了,虽然实际可能不会重复的Write。改进之

var err error
write := func(buf []byte) {
    if err != nil {
        return
    }
    _, err = w.Write(buf)
}
write(p0[a:b])
write(p1[c:d])
write(p2[e:f])
// and so on
if err != nil {
    return err
}

闭包的方式,这里的缺点是需要维护一个err,如果我们想用一些其他的辅助函数,反而甚至会更麻烦。

直接定义一个对象吧

type errWriter struct {
    w   io.Writer
    err error
}
func (ew *errWriter) write(buf []byte) {
    if ew.err != nil {
        return
    }
    _, ew.err = ew.w.Write(buf)
}
ew := &errWriter{w: fd}
ew.write(p0[a:b])
ew.write(p1[c:d])
ew.write(p2[e:f])
// and so on
if ew.err != nil {
    return ew.err
}

例子二

参考Dave Cheney的一篇blog

https://dave.cheney.net/2019/01/27/eliminate-error-handling-by-eliminating-errors

type Header struct {
    Key, Value string
}

type Status struct {
    Code   int
    Reason string
}

func WriteResponse(w io.Writer, st Status, headers []Header, body io.Reader) error {
    _, err := fmt.Fprintf(w, "HTTP/1.1 %d %s
", st.Code, st.Reason)
    if err != nil {
        return err
    }

    for _, h := range headers {
        _, err := fmt.Fprintf(w, "%s: %s
", h.Key, h.Value)
        if err != nil {
            return err
        }
    }

    if _, err := fmt.Fprint(w, "
"); err != nil {
        return err
    }

    _, err = io.Copy(w, body)
    return err
}

这里的问题是下面这个函数都会返回一个err,本质上还是io.Writer的问题

func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
...
}

改进

type errWriter struct {
    io.Writer
    err error
}

func (e *errWriter) Write(buf []byte) (int, error) {
    if e.err != nil {
        return 0, e.err
    }

    var n int
    n, e.err = e.Writer.Write(buf)
    return n, nil
}

type Header struct {
    Key, Value string
}

type Status struct {
    Code   int
    Reason string
}

func WriteResponse(w io.Writer, st Status, headers []Header, body io.Reader) error {
    ew := &errWriter{Writer:w}

    fmt.Fprintf(ew, "HTTP/1.1 %d %s
", st.Code, st.Reason)


    for _, h := range headers {
        fmt.Fprintf(ew, "%s: %s
", h.Key, h.Value)
    }

    fmt.Fprint(w, "
")

    io.Copy(ew, body)
    return ew.err
}

第三个例子

func CountLines(r io.Reader) (int, error) {
    var (
        br    = bufio.NewReader(r)
        lines int
        err   error
    )

    for {
        _, err = br.ReadString('
')
        lines++
        if err != nil {
            break
        }
    }

    if err != io.EOF {
        return 0, err
    }

    return lines, nil
}

改进

func CountLines(r io.Reader) (int, error) {
    sc := bufio.NewScanner(r)
    lines := 0

    for sc.Scan() {
        lines++
    }

    return lines, sc.Err()
}
type Scanner struct {
    r            io.Reader // The reader provided by the client.
    split        SplitFunc // The function to split the tokens.
    maxTokenSize int       // Maximum size of a token; modified by tests.
    token        []byte    // Last token returned by split.
    buf          []byte    // Buffer used as argument to split.
    start        int       // First non-processed byte in buf.
    end          int       // End of data in buf.
    err          error     // Sticky error.
    empties      int       // Count of successive empty tokens.
    scanCalled   bool      // Scan has been called; buffer is in use.
    done         bool      // Scan has finished.
}

可以看到Scanner是高一级的封装对象,Scan() 内部就处理了err

参考

https://blog.huoding.com/2019/04/11/728

end

一个没有高级趣味的人。 email:hushui502@gmail.com
原文地址:https://www.cnblogs.com/CherryTab/p/12831242.html