您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關怎么在Golang中處理重復錯誤,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
_, 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 }
如上代碼乍一看無法直觀的看出其本來的意圖是什么,改進版:
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]) if ew.err != nil { return ew.err }
通過自定義類型 errWriter 來封裝 io.Writer,并且封裝了 error,新類型有一個 write 方法,不過其方法簽名并沒有返回 error,而是在方法內部判斷一旦有問題就立刻返回,有了這些準備工作,我們就可以把原本穿插在業務邏輯中間的錯誤判斷提出來放到最后來統一調用,從而在視覺上保證讓人可以直觀的看出代碼本來的意圖是什么。
讓我們再看看 Eliminate error handling by eliminating errors 中提到的另一個 io.Writer 例子:
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\r\n", st.Code, st.Reason) if err != nil { return err } for _, h := range headers { _, err := fmt.Fprintf(w, "%s: %s\r\n", h.Key, h.Value) if err != nil { return err } } if _, err := fmt.Fprint(w, "\r\n"); err != nil { return err } _, err = io.Copy(w, body) return err }
第一感覺既然錯誤是 fmt.Fprint 和 io.Copy 返回的,是不是我們要重新封裝一下它們?實際上真正的源頭是它們的參數 io.Writer,因為直接調用 io.Writer 的 Writer 方法的話,方法簽名中有返回值 error,所以每一步 fmt.Fprint 和 io.Copy 操作都不得不進行重復的錯誤處理,看上去是壞味道,改進版:
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 } 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\r\n", st.Code, st.Reason) for _, h := range headers { fmt.Fprintf(ew, "%s: %s\r\n", h.Key, h.Value) } fmt.Fprint(ew, "\r\n") io.Copy(ew, body) return ew.err }
通過自定義類型 errWriter 來封裝 io.Writer,并且封裝了 error,同時重寫了 Writer 方法,雖然方法簽名中仍然有返回值 error,但是我們單獨保存了一份 error,并且在方法內部判斷一旦有問題就立刻返回,有了這些準備工作,新版的 WriteResponse 不再有重復的錯誤判斷,只需要在最后檢查一下 error 即可。
類似的做法在 Golang 標準庫中屢見不鮮,讓我們繼續看看 Eliminate error handling by eliminating errors 中提到的一個關于 bufio.Reader 和 bufio.Scanner 的例子:
func CountLines(r io.Reader) (int, error) { var ( br = bufio.NewReader(r) lines int err error ) for { _, err = br.ReadString('\n') lines++ if err != nil { break } } if err != io.EOF { return 0, err } return lines, nil }
我們構造一個 bufio.Reader,然后在一個循環中調用 ReadString 方法,如果讀到文件結尾,那么 ReadString 會返回一個錯誤(io.EOF),為了判斷此類情況,我們不得不在每次循環時判斷「if err != nil」,看上去這是壞味道,改進版:
func CountLines(r io.Reader) (int, error) { sc := bufio.NewScanner(r) lines := 0 for sc.Scan() { lines++ } return lines, sc.Err() }
實際上,和 bufio.Reader 相比,bufio.Scanner 是一個更高階的類型,換句話簡單點來說的話,相當于是 bufio.Scanner 抽象了 bufio.Reader,通過把低階的 bufio.Reader 換成高階的 bufio.Scanner,循環中不再需要判斷「if err != nil」,因為 Scan 方法簽名不再返回 error,而是返回 bool,當在循環里讀到了文件結尾的時候,循環直接結束,如此一來,我們就可以統一在最后調用 Err 方法來判斷成功還是失敗,看看 Scanner 的定義:
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. }
golang可以做服務器端開發,但golang很適合做日志處理、數據打包、虛擬機處理、數據庫代理等工作。在網絡編程方面,它還廣泛應用于web應用、API應用等領域。
關于怎么在Golang中處理重復錯誤就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。