Golang中重複錯誤處理的優化方法

2022-09-24 14:45:22 字數 3206 閱讀 3100

golang 錯誤處理最讓人頭疼的問題就是**裡充斥著「if err != nil」,它們破壞了**的可讀性,本文收集了幾個例子,讓大家明白如何優化此類問題。

讓我們看看 errors are values 中提到的乙個 io.writer 例子:

_, err = fd.write(p0[a:b])

if err != nil

_, err = fd.write(p1[c:d])

if err != nil

_, err = fd.write(p2[e:f])

if err != nil

如上**乍一看無法直觀的看出其本來的意圖是什麼,改進版:

type errwriter struct

func (ew *errwriter) write(buf byte)

_, ew.err = ew.w.write(buf)

}ew := &errwriter

ew.write(p0[a:b])

ew.write(p1[c:d])

ew.write(p2[e:f])

if ew.err != nil

通過自定義型別 errwriter 來封裝 io.writer,並且封裝了 error,新型別有乙個 write 方法,不過其方法簽名並沒有返回 error,而是在方法內部判斷一旦有問題就立刻返回,有了這些準備工作,我們就可以把原本穿插在業務邏輯中間的錯誤判斷提出來放到最後來統一呼叫,從而在視覺上保證讓人可以直觀的看出**本來的意圖是什麼。

讓我們再看看 eliminate error handling by eliminating errors 中提到的另乙個 io.writer 例子:

type header struct

type status struct

func writeresponse(w io.writer, st status, headers header, body io.reader) error

for _, h := range headers

} if _, err := fmt.fprint(w, "\r\n"程式設計客棧); err != nil

_, err = io.copy(w, body)

return err

}第一感覺既然錯誤是 fmt.fprint 和 io.copy 返回的,是不是我們要重新封裝一下它們?實際上真正的源頭是它們的引數 io.writer,因為直接呼叫 io.writer 的 writer 方法的話,方法簽名中有返回值 error,所以每一步 fmt.fprint 和 io.copy 操作都不得不進行重複的錯誤處理,看上去是壞味道,改進版:

}通過自定義型別 errwriter 來封裝 io.writer,並且封裝了 error,同時重寫了 writer 方法,雖然方法簽名中仍然有返回值 error,但是我們單獨儲存了乙份 error,並且在方法內部判斷一旦有問題就立刻返回,有了這些準備工作,新版的 writeresponse 不再有重複的錯誤判斷,只需要在最後檢查一下 error 即可。

類似的做法在 golang 標準庫中屢見不鮮,讓我們繼續看看 eliminate error handling by eliminating errors 中提到的乙個關於 bufio.reader 和 bufio.scanner 的例子:

func countlin程式設計客棧es(r io.reader) (int, error)

} if err != io.eof

return lines, nil

}我們構造乙個 bufio.reader,然後在乙個迴圈中呼叫 readstring 方法,如果讀到檔案結尾,那麼 readstring 會返回乙個錯誤(io.eof),為了判斷此類情況,我們不得不在每次迴圈時判斷「if err != nil」,看上去這是壞味道,改進版:

func countlines(r io.reader) (int, error)

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

可見 scanner 封裝了 io.reader,並且封裝了 error,和我們之前討論的做法一致。有一點說明一下,實際上檢視 scan 源**的話,你會發現它不是通過 err 來判斷是否結束的,而是通過 done 來判斷是否結束,這是因為 scan 只有遇到檔案結束的錯誤才退出,其它錯誤會繼續執行,當然,這只是具體的細節問題,不影響我們的結論。

通過對以上幾個例子的分析,我們可以得出優化重複錯誤處理的大概套路:通過建立新的型別來封裝原本幹髒活累活的舊型別,同時在新型別中封裝 error,新舊型別的方法簽名可以保持相容,也可以不相容,這個不是關鍵的,視客觀情況而定,至於具體的邏輯實現,先判斷有沒有 error,如果有就直接退出,如果沒有就繼續執行,並且在執行過程中儲存可能出現的 error 以便後面操作使用,最後通過統一呼叫新型別的 error 來完成錯誤處理。提醒一下,此方案的缺點是要到最後才能知道有沒有錯誤,好在如此的控制粒度在多數時候並無大礙。

總結本文標題: golang中重複錯誤處理的優化方法

本文位址: /jiaoben/golang/257060.html

如何優化Golang中重複的錯誤處理

golang 錯誤處理最讓人頭疼的問題就是 裡充斥著 if err nil 它們破壞了 的可讀性,本文收集了幾個例子,讓大家明白如何優化此類問題。讓我們看看 errors are values 中提到的乙個 io.writer 例子 err fd.write p0 a b if err nil er...

golang 錯誤處理

go 程式使用 error 值來表示錯誤狀態。與 fmt.stringer 類似,error 型別是乙個內建介面 type error inte ce 與 fmt.stringer 類似,fmt 包在列印值時也會滿足 error。通常函式會返回乙個 error 值,呼叫的它的 應當判斷這個錯誤是否等...

golang 錯誤處理

一 defer package main import fmt os bufio func trydefer func writefile filename string else return defer file.close 無論return panic最後都會被執行 writer bufio....