Go 函數(shù)返回nil遇到問題避坑分析
前言
go語言寫函數(shù)時(shí)經(jīng)常返回nil,然后在函數(shù)外面判斷返回值是否為空。這里有個(gè)bug,記錄一下
問題1
(*Type)(nil) ≠ nil
func returnsError() error { var p *MyError = nil if bad() { p = ErrBad } return p // Will always return a non-nil error. }
上面函數(shù)returnsError返回的 p 永遠(yuǎn)不會(huì)與 nil 相等。
這是為什么呢,因?yàn)?error 是一個(gè) interface,interface 之間比較需要保證兩者的 Type 和 Value 兩兩相等
語言內(nèi)的 nil 可以理解為一個(gè) Type 和 Value 均為空的 interface 代碼里面返回的 p 雖然 Value 為空,但是 Type 是 *MyError 所以 p!=nil 。
正確寫法
func returnsError() error { if bad() { return ErrBad } return nil }
這個(gè)問題不僅僅是拋出錯(cuò)誤的時(shí)候會(huì)出現(xiàn),任何返回 interface 的場景都需要注意。
問題2
type CustomError struct { Metadata map[string]string Message string } func (c CustomError) Error() string { return c.Message } var ( ErrorA = CustomError{Message:"A", Matadata: map[string]string{"Reason":""}} ErrorB = CustomError{Message:"B"} ) func DoSomething() error { return ErrorA }
而我們在外部接收到錯(cuò)誤之后常常會(huì)使用 errors.Is 來判斷錯(cuò)誤類型:
err:=DoSomething() if errors.Is(err, ErrorA) { // handle err }
但是會(huì)發(fā)現(xiàn)上面這個(gè)判斷無論如何都是 false。研究一下 errors.Is 的源碼:
func Is(err, target error) bool { if target == nil { return err == target } isComparable := reflect.TypeOf(target).Comparable() for { if isComparable && err == target { return true } if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) { return true } if err = errors.Unwrap(err); err == nil { return false } } }
可以看到這是一個(gè)在 error tree 上遞歸的流程,真值的終結(jié)條件是 err==target ,但是前提是 target 本身得是 comparable 的
所以如果我們把一個(gè) map 放入了 error struct,就導(dǎo)致這個(gè) error 變?yōu)?incomparable,永遠(yuǎn)無法成功比較。
解決方案也很簡單,就是將 Error 定義指針類型:
var ( ErrorA = &CustomError{Message:"A", Matadata: map[string]string{"Reason":""}} ErrorB = &CustomError{Message:"B"} )
指針類型比較只需要是否檢查是否指向同一個(gè)對象,這樣就能順利比較了。
參考
以上就是Go 函數(shù)返回nil遇到問題避坑分析的詳細(xì)內(nèi)容,更多關(guān)于Go 函數(shù)返回nil避坑的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
幾個(gè)小技巧幫你實(shí)現(xiàn)Golang永久阻塞
Go 的運(yùn)行時(shí)的當(dāng)前設(shè)計(jì),假定程序員自己負(fù)責(zé)檢測何時(shí)終止一個(gè) goroutine 以及何時(shí)終止該程序。有時(shí)候我們需要的是使程序阻塞在這一行,本文就來詳細(xì)的介紹一下,感興趣的可以了解一下2021-12-12go語言調(diào)用c語言的so動(dòng)態(tài)庫的實(shí)現(xiàn)
在Go語言開發(fā)過程中,有時(shí)需要調(diào)用C或C++編寫的so動(dòng)態(tài)庫,本文介紹了如何在Go語言中調(diào)用so庫的步驟和注意事項(xiàng),包括環(huán)境準(zhǔn)備、編譯生成.so文件、Go文件編寫、以及可能遇到的問題和解決方法,感興趣的可以了解一下2024-10-10Go 微服務(wù)開發(fā)框架DMicro設(shè)計(jì)思路詳解
這篇文章主要為大家介紹了Go 微服務(wù)開發(fā)框架DMicro設(shè)計(jì)思路詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10