成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網
最全最豐富的資訊網站

golang的接口有啥用

在golang中,接口是一種類型,是用來將對方法進行一個收束,其作用是:1、作為方法的收束器,進行面向對象設計;2、作為各種數據的承載者,可以用來接收函數參數等。接口的定義語法“type 接口類型名 interface{方法名( 參數列表1 ) 返回值列表}”;當方法名首字母是大寫且這個接口類型名首字母也是大寫時,這個方法可以被接口所在的包(package)之外的代碼訪問。

golang的接口有啥用

本教程操作環境:windows7系統、GO 1.18版本、Dell G3電腦。

一、接口(interface)是什么

interface是一組method簽名的組合,我們通過interface來定義對象的一組行為。

(注意method 和普通func的區別)

Interface是一種類型,和往常語言的接口不一樣,它只是用來將對方法進行一個收束。然而正是這種收束,使GO語言擁有了基于功能的面向對象。

接口的主要功能:

1.作為方法的收束器,進行面向對象設計。

2.作為各種數據的承載者,可以用來接收函數參數等。

這也是,GO語言提倡面向接口編程

二、接口的定義使用

2.1定義

類似結構體

type 接口類型名 interface{     方法名1( 參數列表1 ) 返回值列表1     方法名2( 參數列表2 ) 返回值列表2     … }
登錄后復制

當然這只是有方法的接口定義,面向數據的接口不用。

  • 接口名:使用type將接口定義為自定義的類型名。Go語言的接口在命名時,一般會在單詞后面添加er,如有寫操作的接口叫Writer,有字符串功能的接口叫Stringer等。接口名最好要能突出該接口的類型含義。

  • 方法名:當方法名首字母是大寫且這個接口類型名首字母也是大寫時,這個方法可以被接口所在的包(package)之外的代碼訪問。

  • 參數列表、返回值列表:參數列表和返回值列表中的參數變量名可以省略

2.2使用

一個對象只要全部實現了接口中的方法,那么就實現了這個接口。換句話說,接口就是一個需要實現的方法列表

//定義接口 type FastfoodStore interface{     MakeHamberger()     MakeFriedChips()     MakeSoftDrink() } //定義結構體 type KFC struct{} type HambergerKing struct{}  //實現了接口中所有的方法 func (kfc KFC) MakeHamberger(){     fmt.println("肯德基的漢堡") } func (kfc KFC) MakeFriedChips(){     fmt.println("肯德基的薯條") } func (kfc KFC) MakeSoftDrink(){     fmt.println("肯德基的飲料") }  func (K *HambergerKing) MakeHameberger(){     fmt.println("漢堡王的漢堡") } func (K *HambergerKing) MakeFriedChips(){     fmt.println("漢堡王的薯條") } func (K *HambergerKing) MakeSoftDrink(){     fmt.println("漢堡王的飲料") }
登錄后復制

我們可以看到不同于Java的接口顯式實現,Go的語言是隱式實現的。

  • 在 Java 中:實現接口需要顯式地聲明接口并實現所有方法;
  • 在 Go 中:實現接口的所有方法就隱式地實現了接口;

那么GO語言是如何檢查該類型是否是接口呢?

答:Go 語言只會在傳遞參數、返回參數以及變量賦值時才會對某個類型是否實現接口進行檢查。從類型檢查的過程來看,編譯器僅在需要時才檢查類型,類型實現接口時只需要實現接口中的全部方法,不需要像 Java 等編程語言中一樣顯式聲明。

我們可以看到在上面實現接口的時候,KFC是用結構體對象實現的,而Hamberger king是通過指針實現的兩者有什么不同呢?

答:區別在于我們初始化接口的時候

//結構體初始化和指針初始化 var f faststore = KFC{}             //可以通過編譯 var f faststore = &KFC{}            //可以通過編譯  var f faststore = HambergerKing{}    //無法通過編譯 var f faststore = &HambergerKing{}    //可以通過編譯
登錄后復制

所以在我們使用指針進行實現,結構體初始化時,為啥不行呢?

答:Go 語言在傳遞參數時都是傳值的。

golang的接口有啥用

如上圖所示,無論上述代碼中初始化的變量指針還是結構體,使用 調用方法時都會發生值拷貝:

如上圖左側,對于 &HambergerKing{} 來說,這意味著拷貝一個新的 &HambergerKing{} 指針,這個指針與原來的指針指向一個相同并且唯一的結構體,所以編譯器可以隱式的對變量解引用(dereference)獲取指針指向的結構體;
如上圖右側,對于 HambergerKing{} 來說,這意味著方法會接受一個全新的 HambergerKing{},因為方法的參數是*HambergerKing,編譯器不會無中生有創建一個新的指針;即使編譯器可以創建新指針,這個指針指向的也不是最初調用該方法的結構體;
上面的分析解釋了指針類型的現象,當我們使用指針實現接口時,只有指針類型的變量才會實現該接口;當我們使用結構體實現接口時,指針類型和結構體類型都會實現該接口。當然這并不意味著我們應該一律使用結構體實現接口,這個問題在實際工程中也沒那么重要,在這里我們只想解釋現象背后的原因。

在上面我們說過,interface有兩種用法,現在介紹了其中一種就是作為方法的收束器。那么第二種就是作為數據的承載者

2.3 數據承載者

作為數據容器時,接口就是一個“空”接口,這個空來形容沒有Method。空interface(interface{})不包含任何的method,正因為如此,所有的類型都實現了空interface。空interface對于描述起不到任何的作用(因為它不包含任何的method),但是空interface在我們需要存儲任意類型的數值的時候相當有用,因為它可以存儲任意類型的數值。它有點類似于C語言的void*類型。

需要注意的是,與 C 語言中的 void * 不同,interface{} 類型不是任意類型。如果我們將類型轉換成了 interface{} 類型,變量在運行期間的類型也會發生變化,獲取變量類型時會得到 interface{}。

我們嘗試從底層實現來解釋兩種用法的不同,你會好理解一些。Go 語言使用 runtime.iface 表示第一種接口,使用 runtime.eface 表示第二種不包含任何方法的接口 interface{},兩種接口雖然都使用 interface 聲明,但是由于后者在 Go 語言中很常見,所以在實現時使用了特殊的類型。

golang的接口有啥用

空接口作為函數的參數

使用空接口實現可以接收任意類型的函數參數。

// 空接口作為函數參數 func show(a interface{}) {     fmt.Printf("type:%T value:%vn", a, a) }
登錄后復制

空接口作為map的值

使用空接口實現可以保存任意值的字典。

// 空接口作為map值     var studentInfo = make(map[string]interface{})     studentInfo["name"] = "Wilen"     studentInfo["age"] = 18     studentInfo["married"] = false     fmt.Println(studentInfo) //gin框架的gin.H{}
登錄后復制

三、關于接口類型轉換

interface 可以存儲所有的值,那么自然會涉及到類型轉換這個話題。與此同時,我們也將在這節細說類型轉換中,因為結構體實現和結構體指針實現的接口的異同。

3.1結構體指針實現接口

//我們仍然運用上面快餐店的例子 type Store interface{     MakeHamberger() } type KFC struct{     name string } func (k *KFC) MakeHamberger(){     fmt.println(k.name+"制作了一個漢堡") } func main(){     var s store = &KFC{name:"東街店"}     store.MakeHamberger() }
登錄后復制

這里將上述代碼生成的匯編指令拆分成三部分分析:

1.結構體 KFC 的初始化;

KFC的初始化又可以分為下面幾步:

  • 獲取 KFC 結構體類型指針并將其作為參數放到棧上;

  • 通過 CALL 指定調用 runtime.newobject函數,這個函數會以 KFC 結構體類型指針作為入參,分配一片新的內存空間并將指向這片內存空間的指針返回到 SP+8 上;

  • SP+8 現在存儲了一個指向 KFC 結構體的指針,我們將棧上的指針拷貝到寄存器 DI 上方便操作;

  • 由于 Cat 中只包含一個字符串類型的 Name 變量,所以在這里會分別將字符串地址 &"東街店" 和字符串長度 6 設置到結構體上。

golang的接口有啥用

2.賦值觸發的類型轉換過程;

因為 KFC 結構體的定義中只包含一個字符串,而字符串在 Go 語言中總共占 16 字節,所以每一個 KFC 結構體的大小都是 16 字節。初始化 KFC 結構體之后就進入了將 *KFC 轉換成 Store 類型的過程了:

類型轉換的過程比較簡單,Store 作為一個包含方法的接口,它在底層使用 [runtime.iface] 結構體表示。runtime.iface 結構體包含兩個字段,其中一個是指向數據的指針,另一個是表示接口和結構體關系的 tab 字段,我們已經通過上一段代碼 SP+8 初始化了 KFC 結構體指針,這段代碼只是將編譯期間生成的 runtime.itab 結構體指針復制到 SP 上:

golang的接口有啥用

到這里,我們會發現 SP ~ SP+16 共同組成了 runtime.iface 結構體。

3.調用接口的方法 Quack();

棧上的這個 runtime.iface 也是 MakeHamberger() 方法的第一個入參。通過CALL()完成方法的調用。

3.2 結構體實現接口

//我們仍然運用上面快餐店的例子 type Store interface{     MakeHamberger() } type KFC struct{     name string } func (k KFC) MakeHamberger(){     fmt.println(k.name+"制作了一個漢堡") } func main(){     var s store = KFC{name:"東街店"}     store.MakeHamberger() }
登錄后復制

如果我們在初始化變量時使用指針類型 &KFC{Name: "東街店"} 也能夠通過編譯,不過生成的匯編代碼和上一節中的幾乎完全相同,所以這里也就不分析這個情況了。

初始化 KFC 結構體;

在棧上初始化 KFC 結構體,而上一節的代碼在堆上申請了 16 字節的內存空間,棧上只有一個指向 KFC 的指針。

完成從 KFC 到 Store 接口的類型轉換;

初始化結構體后會進入類型轉換的階段,編譯器會將 go.itab."".KFC,"".Store 的地址和指向 KFC 結構體的指針作為參數一并傳入 runtime.convT2I 函數:這個函數會獲取 runtime.itab 中存儲的類型,根據類型的大小申請一片內存空間并將 elem 指針中的內容拷貝到目標的內存中:

func convT2I(tab *itab, elem unsafe.Pointer) (i iface) {     t := tab._type     x := mallocgc(t.size, t, true)     typedmemmove(t, x, elem)     i.tab = tab     i.data = x     return }
登錄后復制

runtime.convT2I 會返回一個 runtime.iface,其中包含 runtime.itab 指針和 KFC 變量。當前函數返回之后,main 函數的棧上會包含以下數據:

golang的接口有啥用

SP 和 SP+8 中存儲的 runtime.itab 和 KFC 指針是 runtime.convT2I 函數的入參,這個函數的返回值位于 SP+16,是一個占 16 字節內存空間的 runtime.iface 結構體,SP+32 存儲的是在棧上的 KFC 結構體,它會在 runtime.convT2I 執行的過程中拷貝到堆上。

3.3類型斷言

如何將一個接口類型轉換成具體類型?

x.(T)

非空接口

func main() {     var c Store = &KFC{Name: "東街店"}     switch c.(type) {     case *KFC:         kfc := c.(*KFC)         kfc.MakeHamberger()     } }
登錄后復制

因為 Go 語言的編譯器做了一些優化,所以代碼中沒有runtime.iface 的構建過程,不過對于這一節要介紹的類型斷言和轉換沒有太多的影響。

switch語句生成的匯編指令會將目標類型的 hash 與接口變量中的 itab.hash 進行比較

空接口

func main() {     var c interface{} = &KFC{Name: "東街店"}     switch c.(type) {     case *KFC:         kfc := c.(*KFC)         kfc.MakeHamberger()     } }
登錄后復制

上述代碼會在類型斷言時就不是直接獲取變量中具體類型的 runtime._type,而是從 eface._type 中獲取,匯編指令仍然會使用目標類型的 hash 與變量的類型比較.

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
免费无遮挡色视频网站| 国产亚洲午夜高清国产拍精品 | 99久久精品日本一区二区免费 | 亚洲色精品88色婷婷七月丁香| 亚洲人成色777777网站| 影音先锋日日狠狠久久| 985大学排名一览表| 成年动作片AV免费网站| 国产97在线 | 传媒有限公司| 国产裸体舞一区二区三区| 精品国产成人国产在线观看| 久久中文字幕AV一区二区不卡| 欧美成人AⅤ高清免费观看| 日本精品视频一区二区| 无码人妻精一区二区三区老牛| 亚洲国产欧洲综合997久久| 中国人妻被两个老外三P| ZOOM与人性ZOOM怎么同步| 国产AV无码精品色午夜| 好大好硬好深好爽想要20P| 久久综合给合久久国产免费| 强奷漂亮少妇高潮麻豆| 无码人妻丰满熟妇区五十路| 亚洲中文久久精品无码照片| H工口全彩里番库18禁无遮挡| 国产97在线 | 亚洲| 精品无码人妻一区二区三区不卡| 女孩子手脚绑起来嘴用胶带封上 | 亚洲AV无码乱码忘忧草亚洲人| 在厨房娇妻被朋友胯下挺进| 成片在线看一区二区草莓| 国产农村乱人伦精品视频| 久久综合香蕉国产蜜臀AV| 人与野鲁交XXXⅩ视频| 亚洲ⅤA中文字幕无码毛片| 中国亲子伦孑XXⅩ| 国产98色在线 | 国| 久久精品国产亚洲AV无码麻豆| 人妻无码少妇一区二区| 亚洲VA中文字幕无码一二三区| 7777奇米四色眼影| 国产精品门事件AV| 邻居少妇张开腿让我爽了一夜视频| 日韩欧美人妻系列中文字幕一区二区三区 | PETEDAVIDSON鸟多长| 国产乱码精品一品二品| 免费全部高H视频无码| 未满十八岁可以去日本留学吗| 伊人久久大香线蕉亚洲五月天| 父母全家儿女大联欢第14集 | 强奷秘书吸乳免费观看| 亚洲AV无码成人精品网站漏男| 99热久RE这里只有精品小草| 国产免费AV片在线观看| 欧美交换配乱吟粗大视频| 亚洲AV激情无码专区在线播放| 99国产欧美久久久精品| 好男人好资源电影在线播放| 人妻人人做人做人人爱| 亚洲人妻在线视频| 国产成人AAAAA级毛片| 妺妺窝人体色7777777| 亚洲AⅤ无码日韩AV无码网站| CHINA中国人CHINESE| 精品久久一区二区乱码| 日日摸夜夜添夜夜添亚洲女人 | 国产成人亚洲精品无码VR| 美女下部裸体张开腿视频| 午夜三级A三级三点自慰| FREE性满足VIDE0SHD| 精品无码久久久久成人漫画| 天美传媒蜜桃传媒精东| 99国精产品灬源码1688| 精品人体无码一区二区三区| 少妇被躁爽到高潮无码| 7723影视大全在线观看| 精品女同一区二区三区免费站 | 亚洲精品一区二区三浪潮AV | ASS十三小美女ASSPICS| 久久6久久66热这里只是精品| 四季AV一区二区三区免费观看| 97久久国产亚洲精品超碰热| 精品国精品无码自拍自在线| 特黄大片又粗又大又暴| WWW爱射网站AVCOM| 久久综合色一综合色88| 亚洲成人AV一区二区| 国产成人综合五月天久久| 欧美一区二区放荡人妇| 又大又硬又粗再深一点视频| 韩国羞耻漫画免费| 无码人妻精品一区二区蜜桃百度 | 久久精品女人天堂AV| 香蕉AV福利精品导航| 丰满的继牳3中文字幕系列免费 | 久久精品99国产精品日本| 性猛交富婆Ⅹ×××乱大交| 丰满的少妇XXXXX人妻| 秋霞鲁丝片AⅤ无码入口| 中国 韩国 日本 免费看片| 精品人人妻人人爽D∨D| 亚洲AV无码成人精品区在线h | 乱码一卡2卡3卡4卡精品| 亚洲精品无码不卡在线播放| 国产啪精品视频网站免费尤物 | 亚洲色帝国综合婷婷久久| 国产又爽又黄又爽又刺激| 视频一区二区三区在线观看密桃| 啊灬啊别停灬用力啊无码视频| 免费无码不卡视频在线观看| 一区二区狠狠色丁香久久婷婷| 黑人大战亚洲女精品区| 性色AV一区二区三区| 国产成人亚洲综合网站小说| 少妇人妻互换不带套| 成人无码区免费AⅤ片黄瓜视频| 欧美亚洲色综久久精品国产| 18禁强伦姧人妻又大又| 麻豆视传媒官网免费观看| 一本到午夜92版福利| 久久久久亚洲AV无码成人片麻豆 | 高跟丝袜AV专区| 色偷拍 自怕 亚洲 10P| 大色综合色综合网站| 日韩人妻无码精品久久久不卡| 波多野42部无码喷潮在线| 人妻熟妇女的欲乱系列| 办公室撕开奶罩揉吮奶头在线观看| 欧美一区二区三区孕妇精品| JAPONENSISFES中国| 秋霞成人无码电影在线观看| 啊灬啊灬啊灬快灬深视频无遮掩 | 精品人妻一区二区三区四区九九| 亚洲精品成人网线在线播放VA | 亚洲美女高潮久久久久| 精品视频无码一区二区三区| 亚洲伊人色欲综合网| 久久婷婷六月综合色液啪| 伊人色综合一区二区三区| 蜜臀AV一区二区三区四区| 97人妻成人免费视频| 漂亮人妻被黑人久久精品| 成人精品天堂一区二区三区 | 公交车后车座疯狂的做的细节| 天天躁日日躁狠狠躁婷婷高清| 国产精品无码素人福利不卡| 亚洲AVAV电影AV天堂18禁| 娇妻被黑人杂交呻吟| 夜夜未满十八勿进的爽爽影院| 麻豆专媒体一区二区| 69无人区卡一卡二卡| 日本精品VIDEOSSE×少妇| 国产CHINESE男男GAY| 五十路熟妇高熟无码视频| 极品少妇XXXX精品少妇小说| 亚洲综合色区另类AV| 成人av在线播放| 熟肉OVA初恋时间2附前作| 国产山东熟女48嗷嗷叫| 亚洲人ⅤSAⅤ国产精品| 免费A级毛片在线播放| 锕锕锕锕锕锕锕好痛免费网址| 熟女俱乐部五十路六十路AV| 国产精品一线二线三线有什么区别| 亚洲xxx色色精选| 免费A级毛片18禁| 成人无码免费视频在线观看网址| 无码人妻精品一区二区蜜桃温柔乡 | 老汉引诱新婚少妇| www.av无码| 无码人妻精品内射一二三AV| 久久99精品久久久久久国产| 8x8x熟妇一区二区三区| 色婷婷综合和线在线| 护士趴下光屁股翘臀被打的作文| 幼儿交1300部多少钱| 日韩AV蜜桃在线观看| 国产人成无码视频在线软件| 一本无码人妻在中文字幕| 人妻丝袜另类欧美偷拍视频| 国产精品无码久久久久久| 亚洲一区二区三区波多野结衣| 欧美日韩一区精品视频一区二区| 国产成人乱码一二三区18| 亚洲熟妇无码乱码AV电影| 欧美人妖XXXX做受| 国产精品无码MV在线观看| 一本一本久久A久久综合精品| 欧美内射AAAAAAXXXXX| 国产精品无码A∨精品影院| 婬乱丰满熟妇XXXXX性| 色优久久久久综合网鬼色| 精品人妻潮喷久久久又裸又黄| AV一区二区三区人妻少妇| 午夜男女爽爽影院免费视频下载 | 久久99精品国产99久久6男男| JAPANESE国产永久| 亚洲av无码成人精品区在线观看| 女人张开腿扒开内裤让男生桶| 国产乱妇乱子在线播放视频|