最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang中重復(fù)錯(cuò)誤處理的優(yōu)化方法

 更新時(shí)間:2019年04月12日 09:54:31   作者:老王  
這篇文章主要給大家介紹了關(guān)于Golang中重復(fù)錯(cuò)誤處理優(yōu)化的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Golang具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

Golang 錯(cuò)誤處理最讓人頭疼的問(wèn)題就是代碼里充斥著「if err != nil」,它們破壞了代碼的可讀性,本文收集了幾個(gè)例子,讓大家明白如何優(yōu)化此類問(wèn)題。

讓我們看看 Errors are values 中提到的一個(gè) 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
}

如上代碼乍一看無(wú)法直觀的看出其本來(lái)的意圖是什么,改進(jìn)版:

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
}

通過(guò)自定義類型 errWriter 來(lái)封裝 io.Writer,并且封裝了 error,新類型有一個(gè) write 方法,不過(guò)其方法簽名并沒(méi)有返回 error,而是在方法內(nèi)部判斷一旦有問(wèn)題就立刻返回,有了這些準(zhǔn)備工作,我們就可以把原本穿插在業(yè)務(wù)邏輯中間的錯(cuò)誤判斷提出來(lái)放到最后來(lái)統(tǒng)一調(diào)用,從而在視覺(jué)上保證讓人可以直觀的看出代碼本來(lái)的意圖是什么。

讓我們?cè)倏纯?Eliminate error handling by eliminating errors 中提到的另一個(gè) 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
}

第一感覺(jué)既然錯(cuò)誤是 fmt.Fprint 和 io.Copy 返回的,是不是我們要重新封裝一下它們?實(shí)際上真正的源頭是它們的參數(shù) io.Writer,因?yàn)橹苯诱{(diào)用 io.Writer 的 Writer 方法的話,方法簽名中有返回值 error,所以每一步 fmt.Fprint 和 io.Copy 操作都不得不進(jìn)行重復(fù)的錯(cuò)誤處理,看上去是壞味道,改進(jìn)版:

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
}

通過(guò)自定義類型 errWriter 來(lái)封裝 io.Writer,并且封裝了 error,同時(shí)重寫了 Writer 方法,雖然方法簽名中仍然有返回值 error,但是我們單獨(dú)保存了一份 error,并且在方法內(nèi)部判斷一旦有問(wèn)題就立刻返回,有了這些準(zhǔn)備工作,新版的 WriteResponse 不再有重復(fù)的錯(cuò)誤判斷,只需要在最后檢查一下 error 即可。

類似的做法在 Golang 標(biāo)準(zhǔn)庫(kù)中屢見不鮮,讓我們繼續(xù)看看 Eliminate error handling by eliminating errors 中提到的一個(gè)關(guān)于 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
}

我們構(gòu)造一個(gè) bufio.Reader,然后在一個(gè)循環(huán)中調(diào)用 ReadString 方法,如果讀到文件結(jié)尾,那么 ReadString 會(huì)返回一個(gè)錯(cuò)誤(io.EOF),為了判斷此類情況,我們不得不在每次循環(huán)時(shí)判斷「if err != nil」,看上去這是壞味道,改進(jìn)版:

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

 for sc.Scan() {
 lines++
 }

 return lines, sc.Err()
}

實(shí)際上,和 bufio.Reader 相比,bufio.Scanner 是一個(gè)更高階的類型,換句話簡(jiǎn)單點(diǎn)來(lái)說(shuō)的話,相當(dāng)于是 bufio.Scanner 抽象了 bufio.Reader,通過(guò)把低階的 bufio.Reader 換成高階的 bufio.Scanner,循環(huán)中不再需要判斷「if err != nil」,因?yàn)?Scan 方法簽名不再返回 error,而是返回 bool,當(dāng)在循環(huán)里讀到了文件結(jié)尾的時(shí)候,循環(huán)直接結(jié)束,如此一來(lái),我們就可以統(tǒng)一在最后調(diào)用 Err 方法來(lái)判斷成功還是失敗,看看 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.
}

可見 Scanner 封裝了 io.Reader,并且封裝了 error,和我們之前討論的做法一致。有一點(diǎn)說(shuō)明一下,實(shí)際上查看 Scan 源代碼的話,你會(huì)發(fā)現(xiàn)它不是通過(guò) err 來(lái)判斷是否結(jié)束的,而是通過(guò) done 來(lái)判斷是否結(jié)束,這是因?yàn)?Scan 只有遇到文件結(jié)束的錯(cuò)誤才退出,其它錯(cuò)誤會(huì)繼續(xù)執(zhí)行,當(dāng)然,這只是具體的細(xì)節(jié)問(wèn)題,不影響我們的結(jié)論。

通過(guò)對(duì)以上幾個(gè)例子的分析,我們可以得出優(yōu)化重復(fù)錯(cuò)誤處理的大概套路:通過(guò)創(chuàng)建新的類型來(lái)封裝原本干臟活累活的舊類型,同時(shí)在新類型中封裝 error,新舊類型的方法簽名可以保持兼容,也可以不兼容,這個(gè)不是關(guān)鍵的,視客觀情況而定,至于具體的邏輯實(shí)現(xiàn),先判斷有沒(méi)有 error,如果有就直接退出,如果沒(méi)有就繼續(xù)執(zhí)行,并且在執(zhí)行過(guò)程中保存可能出現(xiàn)的 error 以便后面操作使用,最后通過(guò)統(tǒng)一調(diào)用新類型的 error 來(lái)完成錯(cuò)誤處理。提醒一下,此方案的缺點(diǎn)是要到最后才能知道有沒(méi)有錯(cuò)誤,好在如此的控制粒度在多數(shù)時(shí)候并無(wú)大礙。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Go java 算法之括號(hào)生成示例詳解

    Go java 算法之括號(hào)生成示例詳解

    這篇文章主要為大家介紹了Go java 算法之括號(hào)生成示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Golang實(shí)現(xiàn)gRPC的Proxy的原理解析

    Golang實(shí)現(xiàn)gRPC的Proxy的原理解析

    gRPC是Google開始的一個(gè)RPC服務(wù)框架, 是英文全名為Google Remote Procedure Call的簡(jiǎn)稱,廣泛的應(yīng)用在有RPC場(chǎng)景的業(yè)務(wù)系統(tǒng)中,這篇文章主要介紹了Golang實(shí)現(xiàn)gRPC的Proxy的原理,需要的朋友可以參考下
    2021-09-09
  • Golang實(shí)現(xiàn)Trie(前綴樹)的示例

    Golang實(shí)現(xiàn)Trie(前綴樹)的示例

    本文主要介紹了Golang實(shí)現(xiàn)Trie(前綴樹)的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • Go內(nèi)置零值標(biāo)識(shí)符zero

    Go內(nèi)置零值標(biāo)識(shí)符zero

    大家學(xué)習(xí)和使用?Go?語(yǔ)言時(shí),有一個(gè)神奇的概念:零值(zero-values),所以本文想給大家分享一個(gè)關(guān)于零值的新提案,目測(cè)已經(jīng)八九不離十了
    2023-08-08
  • Go設(shè)計(jì)模式之代理模式圖文詳解

    Go設(shè)計(jì)模式之代理模式圖文詳解

    這篇文章將通過(guò)圖文講解給大家詳細(xì)的介紹一下Go代理模式,代理模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,代理控制著對(duì)于原對(duì)象的訪問(wèn), 并允許在將請(qǐng)求提交給對(duì)象前后進(jìn)行一些處理,感興趣的同學(xué)跟著小編一起來(lái)看看吧
    2023-07-07
  • 詳解go程序如何在windows服務(wù)中開啟和關(guān)閉

    詳解go程序如何在windows服務(wù)中開啟和關(guān)閉

    這篇文章主要介紹了一個(gè)go程序,如何在windows服務(wù)中優(yōu)雅開啟和關(guān)閉,文中通過(guò)代碼示例和圖文講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-07-07
  • Go語(yǔ)言簡(jiǎn)介和環(huán)境配置

    Go語(yǔ)言簡(jiǎn)介和環(huán)境配置

    Go語(yǔ)言保證了既能到達(dá)靜態(tài)編譯語(yǔ)言的安全和性能,又達(dá)到了動(dòng)態(tài)語(yǔ)言開發(fā)速度和易維護(hù)性,有人形容Go語(yǔ)言:Go=?C?+?Python?,?說(shuō)明Go語(yǔ)言既有C靜態(tài)語(yǔ)言程序的運(yùn)行速度,又能達(dá)到Python動(dòng)態(tài)語(yǔ)言的快速開發(fā),這篇文章主要介紹了Go介紹和環(huán)境配置,需要的朋友可以參考下
    2022-07-07
  • Go Comparable Type原理深入解析

    Go Comparable Type原理深入解析

    這篇文章主要為大家介紹了Go Comparable Type原理深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Golang實(shí)現(xiàn)AES對(duì)稱加密算法實(shí)例詳解

    Golang實(shí)現(xiàn)AES對(duì)稱加密算法實(shí)例詳解

    所謂對(duì)稱加密是指在加密和解碼時(shí)使用同一密鑰的加密方式,下面這篇文章主要給大家介紹了關(guān)于Golang實(shí)現(xiàn)AES對(duì)稱加密算法的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • go goroutine 怎樣進(jìn)行錯(cuò)誤處理

    go goroutine 怎樣進(jìn)行錯(cuò)誤處理

    在 Go 語(yǔ)言程序開發(fā)中,goroutine 的使用是比較頻繁的,因此在日常編碼的時(shí)候 goroutine 里的錯(cuò)誤處理,怎么做會(huì)比較好呢,本文就來(lái)詳細(xì)介紹一下
    2021-07-07

最新評(píng)論

荣成市| 娱乐| 武冈市| 丽江市| 东源县| 广德县| 新泰市| 克山县| 长春市| 固原市| 陆良县| 嫩江县| 金阳县| 洛浦县| 荥经县| 锡林浩特市| 平陆县| 长垣县| 阜南县| 洛隆县| 临汾市| 白玉县| 长春市| 庆元县| 佳木斯市| 阳东县| 睢宁县| 资阳市| 大同县| 绥芬河市| 闽清县| 十堰市| 建水县| 辛集市| 南涧| 综艺| 麟游县| 环江| 土默特右旗| 连山| 静乐县|