譯 go錯誤處理

2021-09-12 18:46:44 字數 4860 閱讀 8462

func open(name string) (file *file, err error)
下面的**使用os.open來開啟乙個檔案。如果出現錯誤,會呼叫log.fatal列印出錯誤的資訊並且終止**。

f, err := os.open("filename.etx")

if err != nil

// do something with the open *file f

在使用go的工作中,上面的例子已經能滿足大多數情況,但是這篇文章會更進一步的**關於捕獲異常的實踐。

error型別是乙個inte***ce型別。乙個error變數可以通過任何可以描述自己的string型別的值來展示自己。下面是它的介面描述:

type error inte***ce
error型別,就像其他內建型別一樣,==是在全域性中預先宣告的==。這意味著我們不用匯入就可以在任何地方使用它。

最常用的error實現是在 errors 包中定義的乙個不可匯出的型別:errorstring

// errorstring is a trivial implementation os error.

type errorstring struct

func (e *errorstring) error() string

通過errors.new函式可以建立乙個errorstring例項.該函式接收乙個string引數,並將string引數轉換為乙個erros.errorstring,然後返回乙個error值.

// new returns an error that formats as the given text.

func new(text string) error

}

下面是如何使用errors.new的例子

func sqrt(f float64) (float64, error) 

// implementation

}

在呼叫sqrt時,如果傳入的引數是負數,呼叫者會接收到sqrt返回的乙個非空error值(正確來說應該是乙個errors.errorstring值)。呼叫者可以通過呼叫errorerror方法或者通過列印來得到錯誤資訊字段("math: squara root of nagative number")。

f, err := sqrt(-1)

if err != nil

fmt包通過呼叫error()方法來格式化error

乙個error介面的責任是總結錯誤的內容。os.open的錯誤返回的格式是像"open /etc/passwd: permission denied"這樣的格式, 而不僅僅只是"permission denied"。sqrt返回的錯誤缺少了關於非法引數的資訊。

為了讓資訊更加明確,比較好用的乙個函式是fmt包裡面的errorf。它根據printf的規則來函格式化乙個字串並且返回,就像使用errors.new建立的error值。

if f < 0
很多情況下,fmt.errorf已經能夠滿足我們了,但是有時候我們還需要更多的細節。我們知道error是乙個介面,因此你可以定義任意的資料型別來作為error值,以供呼叫者獲取更多的錯誤細節。

例如,如果有乙個比較複雜的呼叫者想要恢復傳給sqrt的非法引數。我們通過定義乙個新的錯誤實現而不是使用errors.errorstring來實現這個需求:

type negativesqrterror float64

func (f negativesqrterror) error() string

乙個複雜的呼叫者就可以使用型別斷言(type assertion)來檢測negativesqrterror並且捕獲它,與此同時,對於使用fmt.println或者log.fatal來輸出錯誤的方式來說卻沒有改變他們的行為。

另乙個例子來自json包,當我們在使用json.decode函式時,如果我們傳入了乙個不合格的json欄位,函式返回syntaxerror型別錯誤。

type syntaxerror struct 

func (e *syntaxerror) error() string

我們可以看到, offset甚至還沒有在預設的errorerror函式**現,但是呼叫者可以用它來生成帶有檔名和行號的錯誤資訊。

if err := dec.decode(&val); err != nil 

return err

}

(這是專案camlistore中的**的乙個簡化版實現)

內建的error介面只需要實現error方法;特定的error實現可能會新增其他的一些附加方法。例如net包,net包內有很多種error型別,通常跟常用的error一樣,但是有些error實現新增一些附加方法,這些附加方法通過net.error介面定義:

package net

type error inte***ce

客戶端**可以通過型別斷言來檢測乙個net.error錯誤以區分這是乙個暫時性錯網路誤還是乙個永久性錯誤。例如當乙個網路爬蟲遇到乙個錯誤時,如果是暫時性錯誤,它會睡眠一下然後在重試,否則停止嘗試。

if nerr, ok := err.(net.error); ok && nerr.temporary() 

if err != nil

go中,錯誤捕獲是很重要的。go的語言特性和使用習慣鼓勵你在錯誤發生時做出明確的檢測(這和那些丟擲異常的然後有時捕獲他們的語言有些區別)。在某些情況,這種方式會造成go**的冗餘,不過幸運的是我們能使用一些技術來減少這種重複的捕獲操作。

}這個函式捕獲從datastore.get函式和viewtemplate.excute方法返回的錯誤。這兩種情況都返回帶http狀態碼為500的簡單的錯誤資訊。上面的**看起來也不多,可以接受,但是如果新增更多的 http handlers情況就不一樣了,你馬上會發現很多這樣的重複**來處理這些錯誤。

然後我們可以更改viewrecord函式,讓它將錯誤返回:

(通常,相對於返回乙個error返回乙個特定型別的錯誤是不對的,具體原因可以參考go fqa , 但是在這裡是正確的,因為這個錯誤值只有servehttp會用到它)

這個版本的viewrecord跟原始版本有著相同的長度,但是現在這些放回資訊都有特殊的資訊,我們提供了更為友好的使用者體驗。

適合的錯誤處理是乙個好軟體最基本的要求。通過這篇文章中討論的技術,你應該能寫出更加可靠簡介的go**。

譯 go錯誤處理

func open name string file file,err error 下面的 使用os.open來開啟乙個檔案。如果出現錯誤,會呼叫log.fatal列印出錯誤的資訊並且終止 f,err os.open filename.etx if err nil do something with...

譯 go錯誤處理

func open name string file file,err error 下面的 使用os.open來開啟乙個檔案。如果出現錯誤,會呼叫log.fatal列印出錯誤的資訊並且終止 f,err os.open filename.etx if err nil do something with...

Go 錯誤處理

error型別是乙個介面型別,也是乙個go語言的內建型別。在這個介面型別的宣告中只包含了乙個方法error。這個方法不接受任何引數,但是會返回乙個string型別的結果。它的作用是返回錯誤資訊的字串表示形象。我們使用error型別的方式通常是,在函式宣告結果列表的最後,宣告乙個該型別的結果。同時在呼...