欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

Go語言中interface與nil的區(qū)別是什么

小編給大家分享一下Go語言中interface與nil的區(qū)別是什么,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

創(chuàng)新互聯(lián)公司是一家以網(wǎng)絡(luò)技術(shù)公司,為中小企業(yè)提供網(wǎng)站維護(hù)、成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、網(wǎng)站備案、服務(wù)器租用、申請(qǐng)域名、軟件開發(fā)、小程序制作等企業(yè)互聯(lián)網(wǎng)相關(guān)業(yè)務(wù),是一家有著豐富的互聯(lián)網(wǎng)運(yùn)營推廣經(jīng)驗(yàn)的科技公司,有著多年的網(wǎng)站建站經(jīng)驗(yàn),致力于幫助中小企業(yè)在互聯(lián)網(wǎng)讓打出自已的品牌和口碑,讓企業(yè)在互聯(lián)網(wǎng)上打開一個(gè)面向全國乃至全球的業(yè)務(wù)窗口:建站來電聯(lián)系:18980820575

interface簡(jiǎn)介

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

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

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

任何類型只要它提供了Read和Write的綁定函數(shù)實(shí)現(xiàn),Go就認(rèn)為這個(gè)類型實(shí)現(xiàn)了這個(gè)interface(duck-type),而不像Java需要開發(fā)者使用implements標(biāo)明。

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

一次真實(shí)的踩坑

這是我們?cè)贕oWorld分布式游戲服務(wù)器的開發(fā)中,碰到的一個(gè)實(shí)際的bug。由于GoWorld支持多種不同的數(shù)據(jù)庫(包括MongoDB,redis等)來保存服務(wù)端對(duì)象,因此GoWorld在上層提供了一個(gè)統(tǒng)一的對(duì)象存儲(chǔ)接口定義,而不同的對(duì)象數(shù)據(jù)庫實(shí)現(xiàn)只需要實(shí)現(xiàn)EntityStorage接口所提供的函數(shù)即可。

// EntityStorage defines the interface of entity storage backends
type 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
}

以一個(gè)使用Redis作為對(duì)象數(shù)據(jù)庫的實(shí)現(xiàn)為例,函數(shù)OpenRedis連接Redis數(shù)據(jù)庫并最終返回一個(gè)redisEntityStorage對(duì)象的指針。

// OpenRedis opens redis as entity storage
func 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函數(shù)連接Redis數(shù)據(jù)庫,并將返回的redisEntityStorage指針賦值個(gè)一個(gè)EntityStorage接口變量,因?yàn)閞edisEntityStorage對(duì)象實(shí)現(xiàn)了EntityStorage接口所定義的所有函數(shù)。

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

上面的代碼看起來都很正常,OpenRedis在連接Redis數(shù)據(jù)庫失敗的時(shí)候會(huì)返回nil,然后調(diào)用者將返回值和nil進(jìn)行比較,來判斷是否連接成功。這個(gè)就是Go語言少有的幾個(gè)深坑之一,因?yàn)椴还躉penRedis函數(shù)是否連接Redis成功,都會(huì)運(yùn)行連接成功的邏輯。

尋找問題所在

想要理解這個(gè)問題,首先需要理解interface{}變量的本質(zhì)。在Go語言中,一個(gè)interface{}類型的變量包含了2個(gè)指針,一個(gè)指針指向值的類型,另外一個(gè)指針指向?qū)嶋H的值。 我們可以用如下的測(cè)試代碼進(jìn)行驗(yàn)證。

// InterfaceStructure 定義了一個(gè)interface{}的內(nèi)部結(jié)構(gòu)
type InterfaceStructure struct {
 pt uintptr // 到值類型的指針
 pv uintptr // 到值內(nèi)容的指針
}

// asInterfaceStructure 將一個(gè)interface{}轉(zhuǎn)換為InterfaceStructure
func 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{} = 16
i1 aaaaaaaaaaaaaaa {pt:5328736 pv:825741282816}
i2 bbbbbbbbbbbbbbb {pt:5328736 pv:825741282824}
nil interface = {pt:0 pv:0}

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

當(dāng)我們將一個(gè)具體類型的值賦值給一個(gè)interface類型的變量的時(shí)候,就同時(shí)把類型和值都賦值給了interface里的兩個(gè)指針。如果這個(gè)具體類型的值是nil的話,interface變量依然會(huì)存儲(chǔ)對(duì)應(yīng)的類型指針和值指針。

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

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

如何解決這個(gè)問題

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

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

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

// OpenRedis opens redis as entity storage
func 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
}

以上是“Go語言中interface與nil的區(qū)別是什么”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!

當(dāng)前題目:Go語言中interface與nil的區(qū)別是什么
本文URL:http://aaarwkj.com/article28/pegijp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供電子商務(wù)、營銷型網(wǎng)站建設(shè)、手機(jī)網(wǎng)站建設(shè)App設(shè)計(jì)、動(dòng)態(tài)網(wǎng)站網(wǎng)站改版

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站優(yōu)化排名
日韩精品诱惑一区二区| 日韩免费色视频一区| 蜜桃午夜精品一区二区三区| 日韩精品高清不卡一区二区三区| 在线播放欧美视频91| 亚洲一区二区日韩在线| 亚洲综合色婷婷七月丁香| 国产欧美日韩91成人| 中国女人内射91熟女| 日韩精品诱惑一区二区| 未满十八周岁禁看视频| 欧美亚洲少妇人妻系列| 九九热这里只有免费视频| 欧美国产综合欧美一区二区三区| 国产麻豆剧传媒国产av| 日韩高清不卡免费视频| 亚洲国产韩国精品在线| 久久女同互慰一区二区三区| 高清av中文免费在线| 岛国av不卡一二三区| 老熟妇奂伦一区二区三区| 国内外成人皇色视频| 97视频在线观看网站| 国产乱码精品免费一区二区av| 美女呻吟被爽到高潮在线| 美女床上激情啪啪网页| 国语自产精品视频在线不卡| 亚洲国产精品一区二区三| av毛片高清在线观看| 亚洲欧美日韩精品在线观看| 看看永久成人免费视频| 欧美日韩亚洲一区视频| 美国一级黄片在线观看| 国产精品国产三级国产av丨| 色哟哟亚洲精品一区二区| 色老头视频一区二区三区| 久久精品噜噜噜成人av农村| 国产精品一区二区一牛影视| 亚洲欧美日韩精品成人| 日韩中文字幕乱码一区| 国产传媒剧情剧资源网站|