這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。這將是一個簡短的文章,靈感來源於 Sean Kelly 十一月份的推特。> 我發現了一個在 golang 中使用指定的傳回值的原因並且現在我感到潸然淚下。 > — Sean Kelly (@StabbyCutyou) 2017年11月15日其目標是為了記錄並說明一種有必要使用到命名返回變數的情況,所以說讓我們進入正題。想象你正在編寫一些用了可能 panic 的函數的代碼,並且無論什麼原因(第三方庫,向後相容,等等)你都不能改變那些函數。```gofunc pressButton() { fmt.Println("I'm Mr. Meeseeks, look at me!!")// other stuff then happens, but if Jerry asks to // remove 2 strokes from his golf game...panic("It's gettin' weird!")}```你仍然需要用到那個函數,不過如果它發生異常,而你想要捕獲到這個 panic 並將它作為一個 error 返回,那麼你應該寫一些類似這樣的代碼:```gofunc doStuff() error { var err error// If there is a panic we need to recover in a deferred funcdefer func() {if r := recover(); r != nil {err = errors.New("the meeseeks went crazy!")}}()pressButton()return err}```在 Go Playground 上執行它 - https://play.golang.org/p/wzkjKGqFPL之後你 go run 了你的代碼然而...這是什嗎?你的 error 是 `nil` 值,甚至是在代碼發生異常的時候。這並不是我們想要的!## 為什麼會發生這種情況?雖然最初看起來我們的代碼返回的是我們在函數開始時建立的 `var err error`,但事實上,我們的程式永遠不會到達這一行代碼。這意味著它永遠不會返回特定的 err 變數,而且在我們的 defer 函數內部改變它,最終會變得毫無意義。在調用 `pressButton` 之後添加一個 `Println`,但在返回之前,確實有助於說明這一點:```gopressButton() // Nothing below here gets executed!fmt.Println("we got here!") return err ```在 Go Playground 上執行它 - https://play.golang.org/p/Vk0DYs20eB## 我們該如何修複它為了修複這個問題,我們可以簡單地使用命名返回變數。```gofunc doStuff() (err error) { // If there is a panic we need to recover in a deferred funcdefer func() {if r := recover(); r != nil {err = errors.New("the meeseeks went crazy!")}}()pressButton()return err}```在 Go Playground 上執行它 - https://play.golang.org/p/bqGOroPjQJ最終的代碼看起來非常的相似,不過通過命名我們的返回變數,當我們聲明這個函數時,我們的程式將會立刻返回這個 `err` 變數,即使我們從未觸碰到 `doStuff` 函數的末尾的返回語句。由於這個細微的差別,現在我們可以更改被我們 defer 的函數中的 `err` 變數,並且成功地捕獲到這個 panic。
via: https://www.calhoun.io/using-named-return-variables-to-capture-panics-in-go/
作者:Jon Calhoun 譯者:Maple24 校對:polaris1119
本文由 GCTT 原創編譯,Go語言中文網 榮譽推出
本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻嗎?歡迎加入 GCTT!
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯絡我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在本文中標註並保留原文/譯文連結和作者/譯者等資訊。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽
460 次點擊