這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
預覽目錄
本片文章用來記錄我在 Golang 開發學習過程中遇到的有關 error 的一些坑。或許你也遇到,或許你能在這裡找到答案。當然通過 error 的例子,你也應該聯想到其它情境。
err != nil
第一個問題是:為什麼值為 nil 的 error 卻不等於 nil?
思考如下代碼:
package mainimport ( "errors" "fmt")type Err struct { err string}func (e *Err) Error() string { return e.err}func returnErr() *Err { return nil}func main() { var err error err = returnErr() fmt.Println(err, err != nil)}
首先 returnErr() 返回了一個值為 nil 的 *Err,然後賦值給了 err,那麼 fmt 會列印什麼結果?是不是:
<nil> false
錯,它會列印 <nil> true。當時自己也是沒有頭緒,學藝不精,問過大神才知道,這是介面 interface 造成的。具體可以查看 官網 FAQ。
簡單說,interface 被兩個元素 value 和 type 所表示。只有在 value 和 type 同時為 nil 的時候,判斷 interface == nil 才會為 true。而 err = returnErr() 這個過程中,雖然 value 為 nil,但 type 卻為 *Err。
如何解決這個問題呢?在我看來只能從根源上著手,兩種方式:
- 不要將該結果賦給一個介面變數。如,將
err = returnErr()改成 err1 := returnErr(),這樣就可以避免造成的幹擾。
不要讓函數返回自訂類型,如,*Err。應該將錯誤封裝過濾為 error,如:
func Err() (err error) { if e := returnErr(); e != nil { return e } return}
err == nil
為什麼還有 err == nil的問題呢?這個問題是我看查看標準庫源碼的時候發現的,其中有這麼一段:
func (e *AddrError) Error() string { if e == nil { // 請注意,為什麼這裡會判斷是否為 nil return "<nil>" } s := e.Err if e.Addr != "" { s = "address " + e.Addr + ": " + s } return s}
為什麼會再次去判斷 e == nil,當時很是費解。眾所周知,方法(姑且這樣說)和變數是儲存在不同地區的,當我們用一個null 指標類型的變數(如,var e *AddrError)調用方法時,該方法是會執行的,只有在執行該null 指標變數的解指標操作時,才會 panic。
下面是一個例子:
// Package main provides ...package mainimport "fmt"func main() { var e *Err e.Print() e.Printf() e.Println()}type Err struct { err string}func (e *Err) Print() { fmt.Println("e.Print run")}func (e *Err) Printf() { fmt.Println(e.err)}func (e Err) Println() { fmt.Println("e.Println run")}
1、e.Print() 是完全可以執行的,沒有解指標操作。
2、e.Printf() 在調用 e.err 的時候,發生瞭解指標操作,故會 panic。
3、e.Println() 由於接受者是 Err 而不是 *Err,Golang 內部在調用該函數時,會自動解指標,故會 panic。
本文連結:https://deepzz.com/post/why-nil-error-not-equal-nil.html,參與評論 »
--EOF--
發表於 2017-05-14 08:55:00,並被添加「golang、error」標籤。
本站使用「署名 4.0 國際」創作共用協議,轉載請註明作者及原網址。更多說明 »
提醒:本文最後更新於 105 天前,文中所描述的資訊可能已發生改變,請謹慎使用。