亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Golang > 正文

Go語言interface 與 nil 的比較

2020-04-01 19:04:10
字體:
來源:轉載
供稿:網友

interface簡介

Go語言以簡單易上手而著稱,它的語法非常簡單,熟悉C++,Java的開發者只需要很短的時間就可以掌握Go語言的基本用法。

interface是Go語言里所提供的非常重要的特性。一個interface里可以定義一個或者多個函數,例如系統自帶的io.ReadWriter的定義如下所示:

type ReadWriter interface {  Read(b []byte) (n int, err error)  Write(b []byte) (n int, err error)}

任何類型只要它提供了Read和Write的綁定函數實現,Go就認為這個類型實現了這個interface(duck-type),而不像Java需要開發者使用implements標明。

然而Go語言的interface在使用過程中卻有一個特別坑的特性,當你比較一個interface類型的值是否是nil的時候,這是需要特別注意避免的問題。

一次真實的踩坑

這是我們在GoWorld分布式游戲服務器的開發中,碰到的一個實際的bug。由于GoWorld支持多種不同的數據庫(包括MongoDB,Redis等)來保存服務端對象,因此GoWorld在上層提供了一個統一的對象存儲接口定義,而不同的對象數據庫實現只需要實現EntityStorage接口所提供的函數即可。

// EntityStorage defines the interface of entity storage backendstype EntityStorage interface { List(typeName string) ([]common.EntityID, error) Write(typeName string, entityID common.EntityID, data interface{}) error Read(typeName string, entityID common.EntityID) (interface{}, error) Exists(typeName string, entityID common.EntityID) (bool, error) Close() IsEOF(err error) bool}

以一個使用Redis作為對象數據庫的實現為例,函數OpenRedis連接Redis數據庫并最終返回一個redisEntityStorage對象的指針。

// OpenRedis opens redis as entity storagefunc OpenRedis(url string, dbindex int) *redisEntityStorage { c, err := redis.DialURL(url) if err != nil { return nil } if dbindex >= 0 { if _, err := c.Do("SELECT", dbindex); err != nil {  return nil } } es := &redisEntityStorage{ c: c, } return es}

在上層邏輯中,我們使用OpenRedis函數連接Redis數據庫,并將返回的redisEntityStorage指針賦值個一個EntityStorage接口變量,因為redisEntityStorage對象實現了EntityStorage接口所定義的所有函數。

var storageEngine StorageEngine // 這是一個全局變量storageEngine = OpenRedis(cfg.Url, dbindex)if storageEngine != nil {  // 連接成功  ...} else {  // 連接失敗  ...}

上面的代碼看起來都很正常,OpenRedis在連接Redis數據庫失敗的時候會返回nil,然后調用者將返回值和nil進行比較,來判斷是否連接成功。這個就是Go語言少有的幾個深坑之一,因為不管OpenRedis函數是否連接Redis成功,都會運行連接成功的邏輯。

尋找問題所在

想要理解這個問題,首先需要理解interface{}變量的本質。在Go語言中,一個interface{}類型的變量包含了2個指針,一個指針指向值的類型,另外一個指針指向實際的值。 我們可以用如下的測試代碼進行驗證。

// InterfaceStructure 定義了一個interface{}的內部結構type InterfaceStructure struct { pt uintptr // 到值類型的指針 pv uintptr // 到值內容的指針}// asInterfaceStructure 將一個interface{}轉換為InterfaceStructurefunc asInterfaceStructure (i interface{}) InterfaceStructure { return *(*InterfaceStructure)(unsafe.Pointer(&i))}func TestInterfaceStructure(t *testing.T) { var i1, i2 interface{} var v1 int = 0x0AAAAAAAAAAAAAAA var v2 int = 0x0BBBBBBBBBBBBBBB i1 = v1 i2 = v2 fmt.Printf("sizeof interface{} = %d/n", unsafe.Sizeof(i1)) fmt.Printf("i1 %x %+v/n", i1, asInterfaceStructure(i1)) fmt.Printf("i2 %x %+v/n", i2, asInterfaceStructure(i2)) var nilInterface interface{} fmt.Printf("nil interface = %+v/n", asInterfaceStructure(nilInterface))}

這段代碼的輸出如下:

sizeof interface{} = 16i1 aaaaaaaaaaaaaaa {pt:5328736 pv:825741282816}i2 bbbbbbbbbbbbbbb {pt:5328736 pv:825741282824}nil interface = {pt:0 pv:0}

所以對于一個interface{}類型的nil變量來說,它的兩個指針都是0。這是符合Go語言對nil的標準定義的。在Go語言中,nil是零值(Zero Value),而在Java之類的語言里,null實際上是空指針。關于零值和空指針有什么區別,這里就不再展開了。

當我們將一個具體類型的值賦值給一個interface類型的變量的時候,就同時把類型和值都賦值給了interface里的兩個指針。如果這個具體類型的值是nil的話,interface變量依然會存儲對應的類型指針和值指針。

func TestAssignInterfaceNil(t *testing.T) { var p *int = nil var i interface{} = p fmt.Printf("%v %+v is nil %v/n", i, asInterfaceStructure(i), i == nil)}

輸入如下:

<nil> {pt:5300576 pv:0} is nil false

可見,在這種情況下,雖然我們把一個nil值賦值給interface{},但是實際上interface里依然存了指向類型的指針,所以拿這個interface變量去和nil常量進行比較的話就會返回false。

如何解決這個問題

想要避開這個Go語言的坑,我們要做的就是避免將一個有可能為nil的具體類型的值賦值給interface變量。以上述的OpenRedis為例,一種方法是先對OpenRedis返回的結果進行非-nil檢查,然后再賦值給interface變量,如下所示。

var storageEngine StorageEngine // 這是一個全局變量redis := OpenRedis(cfg.Url, dbindex)if redis != nil {  // 連接成功  storageEngine = redis // 確定redis不是nil之后再賦值給interface變量} else {  // 連接失敗  ...}

另外一種方法是讓OpenRedis函數直接返回EntityStorage接口類型的值,這樣就可以把OpenRedis的返回值直接正確賦值給EntityStorage接口變量。

// OpenRedis opens redis as entity storagefunc OpenRedis(url string, dbindex int) EntityStorage { c, err := redis.DialURL(url) if err != nil { return nil } if dbindex >= 0 { if _, err := c.Do("SELECT", dbindex); err != nil {  return nil } } es := &redisEntityStorage{ c: c, } return es}

至于那種方法更好,就見仁見智了。希望大家在實際項目中不要踩坑,即使踩了也能快速跳出來!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲影院色无极综合| 亚洲片国产一区一级在线观看| 中文字幕日韩欧美精品在线观看| 久久精品国产一区| 国产精品久久久久免费a∨| 亚洲999一在线观看www| 亚洲精品国产精品国自产观看浪潮| 亚洲一区二区三区香蕉| 亚洲精品动漫久久久久| 日韩精品免费综合视频在线播放| 国产午夜精品麻豆| 亚洲第一福利在线观看| 欧美影院成年免费版| 日韩欧美在线视频| 亚洲电影免费观看高清| 6080yy精品一区二区三区| 日韩美女福利视频| 欧美成人午夜剧场免费观看| 亚洲天堂男人天堂女人天堂| 亚洲高清免费观看高清完整版| 91免费看片在线| 亚洲精品短视频| 日本伊人精品一区二区三区介绍| 中文字幕精品—区二区| 国产精品露脸av在线| 91精品视频免费看| 日韩av不卡在线| 国产精品第一视频| 欧美午夜激情在线| 国产精品吴梦梦| 亚洲欧美国产另类| 国产91亚洲精品| 久久五月天综合| 久久九九免费视频| 欧美xxxx18国产| 日韩av影片在线观看| 欧亚精品中文字幕| 97婷婷涩涩精品一区| 国产精品第一页在线| 亚洲一区二区三区毛片| 国产精品网址在线| 日韩高清av一区二区三区| 国产成人精品a视频一区www| 日韩欧美在线免费| 亚洲人成电影在线播放| 久久久久久久电影一区| 欧美性猛交xxxxx免费看| 欧美成年人网站| 日韩的一区二区| 日韩av在线播放资源| 色香阁99久久精品久久久| 91免费在线视频| 国产精品对白刺激| 中文字幕在线日韩| 国产精品久久久久久久av大片| 色综合伊人色综合网| 日韩精品视频中文在线观看| 最近2019中文字幕mv免费看| 精品美女永久免费视频| 国产一区二区在线免费| 国产欧美精品xxxx另类| 538国产精品视频一区二区| 国产日韩欧美成人| 欧美一区二区.| 精品香蕉在线观看视频一| 一本一本久久a久久精品牛牛影视| 91黑丝高跟在线| 欧美一级高清免费播放| 日韩精品在线第一页| 日av在线播放中文不卡| 91精品视频一区| 亚洲中国色老太| 国产欧美一区二区三区久久人妖| 亚洲3p在线观看| 国产一区二区三区毛片| 亚洲国产精品久久精品怡红院| 亚洲品质视频自拍网| 欧洲成人在线视频| 青青草原成人在线视频| 欧美性xxxx在线播放| 欧美黄色片在线观看| 久久久久免费精品国产| 91精品久久久久久久久久另类| 精品伊人久久97| 欧美成人午夜激情在线| www.日韩免费| 欧美精品在线观看91| 久久久久久久久久久免费精品| 亚洲精品欧美日韩专区| 亚洲精选在线观看| 欧美电影电视剧在线观看| 国产在线精品成人一区二区三区| 国产在线视频一区| 91chinesevideo永久地址| 亚洲欧美中文日韩在线| 国产精品入口免费视频一| 亚洲欧洲国产一区| 亚洲xxxxx| 久久久久国产精品一区| 国产精品毛片a∨一区二区三区|国| 国产91精品久久久久久| 国产午夜精品理论片a级探花| 97超视频免费观看| 亚洲国产精品va在线看黑人| www.亚洲一二| 欧洲亚洲女同hd| 性欧美办公室18xxxxhd| 欧美日韩精品在线观看| 亚洲bt天天射| 亚洲人成伊人成综合网久久久| 91中文字幕一区| 精品久久久久久久大神国产| 日韩av在线网页| 国产一区二区三区高清在线观看| 国产精品精品久久久久久| 日本韩国欧美精品大片卡二| 操日韩av在线电影| 免费91麻豆精品国产自产在线观看| 亚洲精品中文字幕有码专区| 日韩亚洲一区二区| 日韩av在线影院| 国产成人高清激情视频在线观看| 欧美丰满少妇xxxxx做受| 中文字幕精品av| 欧美成人精品h版在线观看| 亚洲第一在线视频| 美女撒尿一区二区三区| 亚洲综合中文字幕在线观看| 欧美亚洲国产视频| 热99精品里视频精品| 亚洲级视频在线观看免费1级| 日韩av在线最新| 亚洲一区www| 日韩一区二区精品视频| 精品久久中文字幕久久av| 麻豆国产精品va在线观看不卡| 国产欧美日韩丝袜精品一区| 91美女高潮出水| 日韩欧美在线看| 日av在线播放中文不卡| 日韩中文字幕在线视频| 66m—66摸成人免费视频| 欧美成人午夜剧场免费观看| 国内伊人久久久久久网站视频| 97在线观看视频| 成人福利视频网| 国产精品va在线播放| 欧美极品少妇与黑人| 日韩美女av在线| 九九热这里只有精品免费看| 国产成人精品一区二区三区| 国产日韩在线看片| 国产精品盗摄久久久| 成人免费xxxxx在线观看| 国产亚洲精品美女久久久| 欧美www视频在线观看| 亚洲欧美日韩一区在线| 亚洲电影免费观看高清完整版在线| 91久久久久久久久| 精品偷拍各种wc美女嘘嘘| 亚洲老司机av| 国产精品久久久久久久久久小说| 三级精品视频久久久久| 国产91色在线播放|