婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > Go語言interface 與 nil 的比較

Go語言interface 與 nil 的比較

熱門標簽:汕頭小型外呼系統 釘釘有地圖標注功能嗎 建造者2地圖標注 濱州自動電銷機器人排名 黃岡人工智能電銷機器人哪個好 阿里云ai電話機器人 鄭州亮點科技用的什么外呼系統 浙江高頻外呼系統多少錢一個月 惠州電銷防封電話卡

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 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
}

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

// 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函數連接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{}轉換為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}

所以對于一個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 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詳解
  • golang中interface接口的深度解析
  • 淺談Go語言中的結構體struct & 接口Interface & 反射
  • go語言中的interface使用實例
  • Go語言interface詳解
  • Go之interface的具體使用

標簽:駐馬店 東營 阿壩 滄州 泰安 昭通 晉中 瀘州

巨人網絡通訊聲明:本文標題《Go語言interface 與 nil 的比較》,本文關鍵詞  語言,interface,與,nil,的,比較,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Go語言interface 與 nil 的比較》相關的同類信息!
  • 本頁收集關于Go語言interface 與 nil 的比較的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    精品国产三级a在线观看| 蜜桃av噜噜一区二区三区小说| 日韩午夜在线观看| 久久影院午夜论| 亚洲日本在线天堂| 亚洲激情综合网| 欧美一级欧美三级在线观看| 久久99在线观看| 午夜av一区二区三区| 亚洲欧洲在线观看av| 亚洲国产精品精华液网站| 国产成人精品影视| 精品一区二区在线视频| 国产一区二区三区综合| 国产一区二区三区免费| 蜜桃av一区二区三区电影| 亚洲色图一区二区三区| 国产成人精品免费视频网站| 精品久久国产老人久久综合| 亚洲女同一区二区| 日韩不卡一区二区| 国产亚洲精品资源在线26u| www.亚洲色图.com| 国产一区二区h| 尤物视频一区二区| 日本欧美加勒比视频| 日韩精品一二三| 精品美女在线播放| 成a人片国产精品| 欧美日韩国产综合一区二区三区| 国产成人精品免费在线| 91免费国产在线观看| 制服视频三区第一页精品| 久久一区二区三区四区| 精品国产91乱码一区二区三区| 日韩一区欧美小说| 成人综合在线观看| 国产精品伦一区| 欧美网站一区二区| 在线观看视频一区二区欧美日韩| 亚洲欧洲中文日韩久久av乱码| 91日韩在线专区| 亚洲欧美韩国综合色| 中文字幕日韩精品一区| 中文字幕一区二区三区不卡在线| 美腿丝袜亚洲一区| 亚洲综合色在线| 7777女厕盗摄久久久| 久久夜色精品国产噜噜av| 国产日韩欧美电影| 中文字幕亚洲在| 亚洲人成伊人成综合网小说| 综合久久久久久| 奇米影视一区二区三区| 亚洲精品一区二区三区蜜桃下载| 亚洲欧美韩国综合色| 日本欧美一区二区三区乱码| 婷婷中文字幕综合| 日产欧产美韩系列久久99| 国产99精品在线观看| 欧美日韩dvd在线观看| 欧美肥妇bbw| 精品久久久网站| ...中文天堂在线一区| 精品在线亚洲视频| 欧美日韩国产乱码电影| 精品理论电影在线| 亚洲色图欧美偷拍| 香蕉加勒比综合久久| 91福利视频网站| 99久久免费国产| 日韩有码一区二区三区| 色美美综合视频| 国产精品99久久久久久似苏梦涵| 亚洲一区二区三区四区的| 天堂午夜影视日韩欧美一区二区| 国产精品一级片| 欧美精品国产精品| 日韩精品电影在线| 另类小说欧美激情| 午夜精品爽啪视频| 国产亚洲1区2区3区| 国产亚洲一区二区三区四区| 亚洲高清在线视频| 中文字幕亚洲欧美在线不卡| 欧美电影在线免费观看| 国产精品视频yy9299一区| 2017欧美狠狠色| 国产精品每日更新| 国产成人精品免费网站| 久久久精品国产免大香伊| 欧美α欧美αv大片| 色综合亚洲欧洲| 麻豆久久一区二区| 性做久久久久久久免费看| 色狠狠av一区二区三区| 99久久夜色精品国产网站| 99re8在线精品视频免费播放| 色欧美日韩亚洲| 丁香激情综合五月| 99视频精品免费视频| 国产精品一区二区久久精品爱涩| 99精品国产91久久久久久| 一区二区三区在线视频观看58| 亚洲国产一区视频| 成人欧美一区二区三区在线播放| 2020国产成人综合网| 久久久久国产精品麻豆ai换脸| 欧美成人精品1314www| 色噜噜狠狠色综合中国| 91精品国产综合久久精品app | 欧美日韩亚洲国产综合| 国产91精品久久久久久久网曝门 | 99免费精品在线观看| 精品一区二区免费看| 久久先锋影音av鲁色资源网| 国产精品色婷婷| 欧美二区在线观看| 97国产一区二区| 亚洲午夜激情av| 一区二区三区四区av| 欧美精品一级二级三级| 顶级嫩模精品视频在线看| 日韩成人一级大片| 亚洲免费观看高清完整版在线| 91麻豆视频网站| 日本色综合中文字幕| 亚洲最大成人网4388xx| 亚洲一区二区欧美激情| 久久99精品国产.久久久久久| 久久久亚洲午夜电影| 色偷偷88欧美精品久久久| 欧美成人精品福利| 91激情在线视频| 一区二区三区在线高清| 欧美videofree性高清杂交| 亚洲人成影院在线观看| 欧美精品一区二区三区蜜桃| 亚洲成人av电影在线| 丝袜诱惑亚洲看片| 日韩黄色片在线观看| 国产乱妇无码大片在线观看| 91捆绑美女网站| 日本最新不卡在线| 日韩一区二区麻豆国产| 午夜精品福利在线| 91精品久久久久久久91蜜桃| 亚洲综合清纯丝袜自拍| 日韩1区2区日韩1区2区| 欧美视频一区二区| 中文字幕一区二区三中文字幕| 国产xxx精品视频大全| 亚洲精品伦理在线| 精品国产百合女同互慰| 亚洲成人综合视频| 日韩欧美国产三级电影视频| 91看片淫黄大片一级在线观看| 性做久久久久久免费观看| 日韩欧美在线不卡| 丁香激情综合五月| 激情成人综合网| 亚洲五月六月丁香激情| 欧美国产精品专区| 日韩欧美不卡一区| av亚洲精华国产精华精| 男男gaygay亚洲| 三级一区在线视频先锋 | 欧美日韩国产区一| 欧美三级欧美一级| 欧美一区二区在线播放| 久久久久成人黄色影片| 亚洲国产毛片aaaaa无费看| 精品中文字幕一区二区小辣椒| 欧美色图第一页| 欧美在线观看你懂的| 亚洲va韩国va欧美va| 午夜不卡在线视频| 日本一区二区高清| 在线免费观看不卡av| 在线成人免费视频| 午夜视频久久久久久| 国产精品99久| 另类综合日韩欧美亚洲| 亚洲自拍另类综合| 欧美岛国在线观看| 综合自拍亚洲综合图不卡区| 国产麻豆视频精品| 亚洲成av人片在线| 波多野结衣中文字幕一区二区三区 | 日韩欧美一级精品久久| 日韩一区二区免费电影| 亚洲人xxxx| 国产一区二区三区免费在线观看| 亚洲一区二区中文在线| 激情综合网天天干| 亚洲国产一区视频| 717成人午夜免费福利电影| 亚洲视频图片小说| 亚洲一区二区在线视频| 亚洲综合在线五月|