golang err!=nil

今天寫代碼的時候,發(fā)現(xiàn)一個和預(yù)期不符合的邏輯。簡單描述就是把一個值為nil的A類型的error賦值給接口error,和nil比較竟然是false。在此記錄一下。

復(fù)現(xiàn)

代碼如下,自定義一個error類型。然后預(yù)計代碼輸出是<nil> false,但是實際輸出是<nil> true。非常非常奇怪,nil竟然不等于nil

package main

import "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)
}

解決辦法
不要將該結(jié)果賦給一個接口變量。如,將 err = returnErr() 改成 err1 := returnErr()

func main() {
    err := returnErr()
    fmt.Println(err, err != nil)
}

或者和原類型比較

func main() {
    var err error
    err = returnErr()
    var e *Err
    fmt.Println(err, err != e)
}

原因

接口 interface 造成的。具體可以查看 官網(wǎng) FAQ。

簡單說,interface 被兩個元素 value 和 type 所表示。只有在 value 和 type 同時為 nil 的時候,判斷 interface == nil 才會為 true。而 err = returnErr() 這個過程中,雖然 value 為 nil,但 type 卻為 *Err。

下面的內(nèi)容從《Go語言精進之路:從新手到高手編程思想、方法和技巧1》拷貝

接口類型“動靜兼?zhèn)洹钡奶匦詻Q定了它的變量的內(nèi)部表示絕不像靜態(tài)類型(如int、float64)變量那樣簡單。我們可以在$GOROOT/src/runtime/runtime2.go中找到接口類型變量在運行時的表示:

image.png

我們看到在運行時層面,接口類型變量有兩種內(nèi)部表示——eface和iface,這兩種表示分別用于不同接口類型的變量。eface:用于表示沒有方法的空接口(empty interface)類型變量,即interface{}類型的變量。iface:用于表示其余擁有方法的接口(interface)類型變量。這兩種結(jié)構(gòu)的共同點是都有兩個指針字段,并且第二個指針字段的功用相同,都指向當前賦值給該接口類型變量的動態(tài)類型變量的值。
image.png

而iface除了要存儲動態(tài)類型信息之外,還要存儲接口本身的信息(接口的類型信息、方法列表信息等)以及動態(tài)類型所實現(xiàn)的方法的信息,因此iface的第一個字段指向一個itab類型結(jié)構(gòu):
image.png

上面itab結(jié)構(gòu)中的第一個字段inter指向的interfacetype結(jié)構(gòu)存儲著該接口類型自身的信息。interfacetype類型定義如下,該interfacetype結(jié)構(gòu)由類型信息(typ)、包路徑名(pkgpath)和接口方法集合切片(mhdr)組成。
itab結(jié)構(gòu)中的字段_type則存儲著該接口類型變量的動態(tài)類型的信息,字段fun則是動態(tài)類型已實現(xiàn)的接口方法的調(diào)用地址數(shù)組。

參考

Golang 博主走過的有關(guān) error 的一些坑

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容