如何减少重复err
Posted cherrytab
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何减少重复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
以上是关于如何减少重复err的主要内容,如果未能解决你的问题,请参考以下文章