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

首頁 > 編程 > Golang > 正文

golang中interface接口的深度解析

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

一 接口介紹

如果說gorountine和channel是支撐起Go語言的并發模型的基石,讓Go語言在如今集群化與多核化的時代成為一道亮麗的風景,那么接口是Go語言整個類型系列的基石,讓Go語言在基礎編程哲學的探索上達到前所未有的高度。Go語言在編程哲學上是變革派,而不是改良派。這不是因為Go語言有gorountine和channel,而更重要的是因為Go語言的類型系統,更是因為Go語言的接口。Go語言的編程哲學因為有接口而趨于完美。C++,Java 使用"侵入式"接口,主要表現在實現類需要明確聲明自己實現了某個接口。這種強制性的接口繼承方式是面向對象編程思想發展過程中一個遭受相當多質疑的特性。Go語言采用的是“非侵入式接口",Go語言的接口有其獨到之處:只要類型T的公開方法完全滿足接口I的要求,就可以把類型T的對象用在需要接口I的地方,所謂類型T的公開方法完全滿足接口I的要求,也即是類型T實現了接口I所規定的一組成員。這種做法的學名叫做Structural Typing,有人也把它看作是一種靜態的Duck Typing。
    

要這個值實現了接口的方法。

type Reader interface {  Read(p []byte) (n int, err os.Error) }  // Writer 是包裹了基礎 Write 方法的接口。 type Writer interface {  Write(p []byte) (n int, err os.Error) }  var r io.Reader r = os.Stdin r = bufio.NewReader(r) r = new(bytes.Buffer) 

有一個事情是一定要明確的,不論 r 保存了什么值,r 的類型總是 io.Reader ,Go 是靜態類型,而 r 的靜態類型是 io.Reader。接口類型的一個極端重要的例子是空接口interface{},它表示空的方法集合,由于任何值都有零個或者多個方法,所以任何值都可以滿足它。也有人說 Go 的接口是動態類型的,不過這是一種誤解。 它們是靜態類型的:接口類型的變量總是有著相同的靜態類型,這個值總是滿足空接口,只是存儲在接口變量中的值運行時可能被改變。對于所有這些都必須嚴謹的對待,因為反射和接口密切相關。

二  接口類型內存布局

在類型中有一個重要的類別就是接口類型,表達了固定的一個方法集合。一個接口變量可以存儲任意實際值(非接口),只要這個值實現了接口的方法。interface在內存上實際由兩個成員組成,如下圖,tab指向虛表,data則指向實際引用的數據。虛表描繪了實際的類型信息及該接口所需要的方法集。

type Stringer interface {  String() string }  type Binary uint64  func (i Binary) String() string {  return strconv.FormatUint(i.Get(), 2) }  func (i Binary) Get() uint64 {  return uint64(i) }  func main() {  var b Binary = 32  s := Stringer(b)  fmt.Print(s.String()) } 

golang,interface,實現interface,interface數組  

觀察itable的結構,首先是描述type信息的一些元數據,然后是滿足Stringger接口的函數指針列表(注意,這里不是實際類型Binary的函數指針集哦)。因此我們如果通過接口進行函數調用,實際的操作其實就是s.tab->fun[0](s.data) 。是不是和C++的虛表很像?但是他們有本質的區別。先看C++,它為每個類創建了一個方法集即虛表,當子類重寫父類的虛函數時,就將表中的相應函數指針改為子類自己實現的函數,如果沒有則指向父類的實現,當面臨多繼承時,C++對象結構里就會存在多個虛表指針,每個虛表指針指向該方法集的不同部分。我們再來看golang/72899.html">golang/196848.html">golang的實現方式,同C++一樣,golang也為每種類型創建了一個方法集,不同的是接口的虛表是在運行時專門生成的,而c++的虛表是在編譯時生成的(但是c++虛函數表表現出的多態是在運行時決定的).例如,當例子中當首次遇見s := Stringer(b)這樣的語句時,golang會生成Stringer接口對應于Binary類型的虛表,并將其緩存。那么為什么go不采用c++的方式來實現呢?這根c++和golang的對象內存布局是有關系的。

首先c++的動態多態是以繼承為基礎的,在對象構造初始化的時首先會初始化父類,其次是子類,也就是說一個對象的內存布局是虛表,父類部分,子類部分(編譯器不同可能會有差異),當一個父類指針指向子類時,會發生內存的截斷,截斷子類部分(內存地址偏移),但是此時子類的虛表中的函數指針實際上還是指向了自己的實現,所以此時的指針才會調用到子類的虛函數,如果不是虛函數,因為內存已經截斷沒有子類的非虛函數信息了,所以只能調用父類的了,這種繼承關系讓c++的虛表的初始化非常清晰,在一個對象初始化時先調用父類的構造此時虛表跟父類是一樣的,接下來初始化子類,此時編譯器就會去識別子類有沒有覆蓋父類的虛函數,如果有則虛表中相應的函數指針改成自己的虛函數實現指針。

那么go有什么不同呢,首先我們很清楚go是沒有嚴格意義上的繼承的,go的接口不存在繼承關系,只要實現了接口定義的方法都可以成為接口類型,這給go的虛表初始化帶來很大的麻煩,到底有多少類型實現了這個接口,一個類型到底實現了多少接口這讓編譯器很confused。舉個例子,某個類型有m個方法,某接口有n個方法,則很容易知道這種判定的時間復雜度為O(mXn),不過可以使用預先排序的方式進行優化,實際的時間復雜度為O(m+n)這樣看來其實還行那為什么要在運行時生成虛表呢,這不是會拖慢程序的運行速度嗎,注意我們這里是某個類型,某個接口,是1對1的關系,如果有n個類型,n個接口呢,編譯器難道要把之間所有的關系都理清嗎?退一步說就算編譯器任勞任怨把這事干了,可是你在寫過程中你本來就不想實現那個接口,而你無意中給這個類型實現的方法中包含了某些接口的方法,你根本不需要這個接口(況且go的接口機制會導致很多這種無意義的接口實現),你欺負編譯器就行了,這也太欺負人了吧。如果我們放到運行時呢,我們只要在需要接口的去分析一下類型是否實現了接口的所有方法就行了很簡單的一件事。

三 空接口

接口類型的一個極端重要的例子是空接口:interface{} ,它表示空的方法集合,由于任何值都有零個或者多個方法,所以任何值都可以滿足它。 注意,[]T不能直接賦值給[]interface{}

//t := []int{1, 2, 3, 4} wrong //var s []interface{} = t t := []int{1, 2, 3, 4} //right s := make([]interface{}, len(t)) for i, v := range t {  s[i] = v } 
str, ok := value.(string) if ok {  fmt.Printf("string value is: %q/n", str) } else {  fmt.Printf("value is not a string/n") } 

在Go語言中,我們可以使用type switch語句查詢接口變量的真實數據類型,語法如下:

type Stringer interface {   String() string }  var value interface{} // Value provided by caller. switch str := value.(type) { case string:   return str //type of str is string case Stringer: //type of str is Stringer   return str.String() } 

也可以使用“comma, ok”的習慣用法來安全地測試值是否為一個字符串:

str, ok := value.(string) if ok {   fmt.Printf("string value is: %q/n", str) } else {   fmt.Printf("value is not a string/n") } 

四 接口賦值

package main  import ( "fmt" )  type LesssAdder interface {   Less(b Integer) bool   Add(b Integer) }  type Integer int  func (a Integer) Less(b Integer) bool {   return a < b }  func (a *Integer) Add(b Integer) {   *a += b }  func main() {    var a Integer = 1   var b LesssAdder = &a   fmt.Println(b)    //var c LesssAdder = a   //Error:Integer does not implement LesssAdder    //(Add method has pointer receiver) } 

go語言可以根據下面的函數:

func (a Integer) Less(b Integer) bool  

自動生成一個新的Less()方法

func (a *Integer) Less(b Integer) bool  

這樣,類型*Integer就既存在Less()方法,也存在Add()方法,滿足LessAdder接口。 而根據

func (a *Integer) Add(b Integer) 

這個函數無法生成以下成員方法:

func(a Integer) Add(b Integer) {   (&a).Add(b) } 

因為(&a).Add()改變的只是函數參數a,對外部實際要操作的對象并無影響(值傳遞),這不符合用戶的預期。所以Go語言不會自動為其生成該函數。因此類型Integer只存在Less()方法,缺少Add()方法,不滿足LessAddr接口。(可以這樣去理解:指針類型的對象函數是可讀可寫的,非指針類型的對象函數是只讀的)將一個接口賦值給另外一個接口 在Go語言中,只要兩個接口擁有相同的方法列表(次序不同不要緊),那么它們就等同的,可以相互賦值。 如果A接口的方法列表時接口B的方法列表的子集,那么接口B可以賦值給接口A,但是反過來是不行的,無法通過編譯。

五 接口查詢

接口查詢是否成功,要在運行期才能夠確定。他不像接口的賦值,編譯器只需要通過靜態類型檢查即可判斷賦值是否可行。

var file1 Writer = ...if file5,ok := file1.(two.IStream);ok {...}

這個if語句檢查file1接口指向的對象實例是否實現了two.IStream接口,如果實現了,則執行特定的代碼。

在Go語言中,你可以詢問它指向的對象是否是某個類型,比如,

var file1 Writer = ...if file6,ok := file1.(*File);ok {...}

這個if語句判斷file1接口指向的對象實例是否是*File類型,如果是則執行特定的代碼。

slice := make([]int, 0)slice = append(slice, 1, 2, 3)var I interface{} = sliceif res, ok := I.([]int);ok {  fmt.Println(res) //[1 2 3]}

這個if語句判斷接口I所指向的對象是否是[]int類型,如果是的話輸出切片中的元素。

func Sort(array interface{}, traveser Traveser) error {  if array == nil {    return errors.New("nil pointer")  }  var length int //數組的長度  switch array.(type) {  case []int:    length = len(array.([]int))  case []string:    length = len(array.([]string))  case []float32:    length = len(array.([]float32))  default:    return errors.New("error type")  }  if length == 0 {    return errors.New("len is zero.")  }  traveser(array)  return nil}

通過使用.(type)方法可以利用switch來判斷接口存儲的類型。

小結: 查詢接口所指向的對象是否為某個類型的這種用法可以認為是接口查詢的一個特例。接口是對一組類型的公共特性的抽象,所以查詢接口與查詢具體類型區別好比是下面這兩句問話的區別:

你是醫生么?

是。

你是莫莫莫

第一句問話查詢的是一個群體,是查詢接口;而第二個問句已經到了具體的個體,是查詢具體類型。

除此之外利用反射也可以進行類型查詢,會在反射中做詳細介紹。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
黄色成人av在线| 97免费视频在线| 亚洲色图25p| 欧美亚洲第一页| 久久精品这里热有精品| 亚洲福利视频专区| 欧美日韩激情美女| 精品国产乱码久久久久久虫虫漫画| 成人福利在线观看| 一本久久综合亚洲鲁鲁| 欧美日韩亚洲91| 亚洲视频欧洲视频| 亚洲国产欧美一区二区三区同亚洲| 国产精品pans私拍| 懂色av中文一区二区三区天美| 亚洲一区中文字幕在线观看| 欧美高清自拍一区| 国产精品久久久久久久av大片| 91网站免费观看| 久久成人精品视频| 一本色道久久综合狠狠躁篇怎么玩| 久久久亚洲欧洲日产国码aⅴ| 国产精品678| 精品成人久久av| 日韩中文字幕国产| 亚洲男人av在线| 成人av在线亚洲| 亚洲www在线观看| 日韩欧美aⅴ综合网站发布| 国产成人免费91av在线| 欧美日韩高清区| 亚洲成色777777女色窝| 欧美国产日韩xxxxx| 国产丝袜精品视频| 久久久精品亚洲| 狠狠躁夜夜躁人人躁婷婷91| 一夜七次郎国产精品亚洲| 97久久精品人搡人人玩| 精品国产精品自拍| 在线观看视频99| 91po在线观看91精品国产性色| 亚洲国产成人精品女人久久久| 国产精品国产三级国产aⅴ浪潮| 国产中文字幕日韩| 国产+人+亚洲| 久久免费精品日本久久中文字幕| 国a精品视频大全| 国产精品青草久久久久福利99| 97免费视频在线播放| 亚洲国产日韩欧美在线99| 亚洲最大的av网站| 亚洲自拍欧美色图| 91在线观看免费高清完整版在线观看| 欧美极品少妇xxxxⅹ喷水| 国产日韩中文字幕| 欧美国产日韩中文字幕在线| 精品偷拍各种wc美女嘘嘘| 欧美在线一级va免费观看| 欧美情侣性视频| 国产亚洲精品久久久久久| 久久精品99国产精品酒店日本| 日本韩国欧美精品大片卡二| 欧美一级大片视频| 日韩欧美亚洲一二三区| 一区二区三区 在线观看视| 精品综合久久久久久97| 欧美高清videos高潮hd| 在线观看欧美日韩国产| 日韩av电影在线播放| 中文字幕精品一区久久久久| 日韩av在线播放资源| 欧美成人免费全部| 欧美性一区二区三区| 亚洲天堂av高清| 国产精品青青在线观看爽香蕉| 91亚洲va在线va天堂va国| xvideos亚洲| 国产精品嫩草影院一区二区| 国产日产欧美a一级在线| 欧美精品久久久久| 亚洲国产精品va在看黑人| 欧美一级黑人aaaaaaa做受| 欧美极品美女电影一区| 中文字幕在线亚洲| 欧美性理论片在线观看片免费| 国产综合福利在线| 国产精品扒开腿做爽爽爽的视频| 亚洲成av人乱码色午夜| 成人综合国产精品| 久久视频在线看| 精品久久久久久亚洲精品| 亚洲色图在线观看| 亚洲自拍偷拍区| 亚洲精品国产精品国产自| 91精品国产高清久久久久久| 精品久久久香蕉免费精品视频| 亚洲国产精品99| 久久久久亚洲精品成人网小说| 久久精品福利视频| 精品国产一区二区三区久久狼5月| 亚洲欧美三级在线| 国产午夜精品全部视频播放| 91九色国产在线| 久久久久国产精品一区| 精品亚洲国产成av人片传媒| 亚洲精品福利免费在线观看| 亚洲男人的天堂在线| 成人免费xxxxx在线观看| 2018中文字幕一区二区三区| 国产精品白嫩初高中害羞小美女| 日韩在线小视频| 国产亚洲a∨片在线观看| 久久久久www| 久久这里只有精品视频首页| 亚洲精品视频久久| 懂色aⅴ精品一区二区三区蜜月| 欧美老女人在线视频| 欧美黑人巨大xxx极品| 国产福利精品视频| 亚洲一区制服诱惑| 亚洲aa中文字幕| 欧美性猛交xxxxx免费看| 亚洲国产小视频| 国产成人高潮免费观看精品| 国产噜噜噜噜久久久久久久久| 国产精品欧美日韩一区二区| 成人做爽爽免费视频| 国产精品最新在线观看| 成人免费看吃奶视频网站| 国产精品黄页免费高清在线观看| 成人激情视频在线观看| 亚洲白虎美女被爆操| 欧美日韩成人网| 国产亚洲欧美日韩美女| 国产欧美精品一区二区三区-老狼| 亚洲第一中文字幕在线观看| 亚洲一区二区少妇| 欧美国产亚洲精品久久久8v| 亚洲人成电影在线| 国产成人鲁鲁免费视频a| 亚洲第一免费播放区| 在线观看日韩av| 成人免费在线网址| 成人欧美一区二区三区黑人孕妇| 中文字幕在线观看亚洲| 最近2019中文字幕大全第二页| 日韩欧美成人免费视频| 91在线视频精品| 亚洲欧美综合另类中字| 欧美午夜激情小视频| 亚洲精品乱码久久久久久金桔影视| 亚洲香蕉成视频在线观看| 日韩精品丝袜在线| 欧美最猛黑人xxxx黑人猛叫黄| 国产一区二区三区网站| 日韩中文字幕第一页| 91精品国产91久久久久| 精品丝袜一区二区三区| 亚洲美女在线看| 国产xxx69麻豆国语对白| 国产91精品久久久| 亚洲欧洲第一视频| 中文字幕日本欧美| 亚洲最新视频在线|