用 Switch-case 來解決 Go 錯(cuò)誤處理的難題?
大家好,我是煎魚。
在 Go 這門編程語言中,if err != nil 的錯(cuò)誤處理方式,是我們一直關(guān)注的焦點(diǎn)之一。所有的 Go 社區(qū)調(diào)查中,都有希望優(yōu)化和改進(jìn)錯(cuò)誤處理的聲音和各種想法。
春節(jié)期間刷到了一個(gè)由 @Bill Soudan 提出的新提案《proposal: Go 2: support new form of switch statement during variable assignment which jumps to function-wide case blocks[1]》,是針對錯(cuò)誤處理優(yōu)化的,思路還是有些新奇的。
圖片
以往印象里沒有人提過這個(gè)方式。今天分享給大家,一起圍觀和學(xué)習(xí)!
新提案
該提案希望在變量賦值時(shí)能夠支持新的 switch 語句形式。從功能出發(fā),更具體指的是:要支持 switch 跳轉(zhuǎn)到函數(shù)范圍內(nèi)的任意位置的標(biāo)簽。
這個(gè)特性的目的是:簡化繁瑣又重復(fù)的 if err !=nil 的錯(cuò)誤檢查代碼,也可以用于其他邏輯實(shí)現(xiàn)。
具體的對比例子如下。
如果是原本的 Go1 錯(cuò)誤處理的范式。
代碼如下:
func CopyFile(src, dst string) error {
r, err := os.Open(src)
if err != nil {
return err
}
defer r.Close()
w, err := os.Create(dst)
if err != nil {
return err
}
defer w.Close()
if _, err := io.Copy(w, r); err != nil {
return err
}
if err := w.Close(); err != nil {
return err
}
}
要寫比較多的判斷和返回錯(cuò)誤的邏輯,并且這些代碼比正式的調(diào)用代碼還要多。所以也常被人戲稱一個(gè) Go 工程里 80% 都是 if err != nil 等錯(cuò)誤檢查代碼。
基于本文提到的 switch-case 提案進(jìn)行改造。
新的代碼如下:
func CopyFile(src, dst string) error {
r, switch err := os.Open(src)
defer r.Close()
w, switch err := os.Create(dst)
defer w.Close()
_, switch dstErr := io.Copy(w, r)
switch dstErr = w.Close()
return nil
case dstErr != nil:
os.Remove(dst)
err = dstErr
fallthrough
case err != nil:
return fmt.Errorf("copy %s %s: %v", src, dst, err)
}
注意幾個(gè)細(xì)節(jié)點(diǎn):
- switch 關(guān)鍵字在對應(yīng)的 err 變量前作為聲明標(biāo)識。
- case 關(guān)鍵字根據(jù)對應(yīng)的 err 變量,運(yùn)行不同的錯(cuò)誤處理邏輯。
- switch-case 子句可以在同一函數(shù)內(nèi)的不同位置進(jìn)行調(diào)用。
這種 switch-case 的使用方式,從優(yōu)點(diǎn)來看。確實(shí)收攏了統(tǒng)一的錯(cuò)誤處理邏輯,減少了重復(fù)繁瑣的代碼量。
短短的代碼片段,看起來像那么一回事,能一定程度上滿足大家原始的訴求。
缺點(diǎn)的話,個(gè)人認(rèn)為會增加認(rèn)知和邏輯復(fù)雜度。你根本不知道 switch-case,這個(gè) case 他的準(zhǔn)確邏輯位置在哪里。
一旦有人套娃,就非常麻煩了。同時(shí) switch-case 延伸出多種不同的使用方式,會產(chǎn)生二義性,這是一個(gè)折騰的事情。
總結(jié)
今天給大家分享了我所看到的一個(gè) Go 錯(cuò)誤處理的新提案,其本質(zhì)上是利用 switch-case 的新語法機(jī)制,實(shí)現(xiàn)了 err 變量和 case 的關(guān)聯(lián)。以此簡化錯(cuò)誤檢查的邏輯。
軟件開發(fā)是沒有銀彈的。如何引入更優(yōu)雅的錯(cuò)誤處理機(jī)制,且不要帶過來過大的程序員心智負(fù)擔(dān),還要要確保編譯器性能尚可。Go 核心團(tuán)隊(duì)可能是想要在這三個(gè)圈里設(shè)計(jì)一個(gè)最優(yōu)的選擇。
參考資料
[1]
proposal: Go 2: support new form of switch statement during variable assignment which jumps to function-wide case blocks: https://github.com/golang/go/issues/65019