如何在golang中使用interface?很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。
創(chuàng)新互聯(lián)公司是一家以成都網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)、品牌設(shè)計(jì)、軟件運(yùn)維、網(wǎng)站推廣、小程序App開發(fā)等移動(dòng)開發(fā)為一體互聯(lián)網(wǎng)公司。已累計(jì)為辦公空間設(shè)計(jì)等眾行業(yè)中小客戶提供優(yōu)質(zhì)的互聯(lián)網(wǎng)建站和軟件開發(fā)服務(wù)。interface
概覽
與通常以類型層次與繼承為根基的面向?qū)ο笤O(shè)計(jì)(OOP)語(yǔ)言(如C++、Java)不同,Go 的核心思想就是組合(composition)。Go 進(jìn)一步解耦了對(duì)象與操作,實(shí)現(xiàn)了真正的鴨子類型(Duck typing):一個(gè)對(duì)象如果能嘎嘎叫那就能當(dāng)做鴨子,而不是像 C++ 或 Java 那樣需要類型系統(tǒng)去保證:一個(gè)對(duì)象先得是只鴨子,然后才能嘎嘎叫。
type Duck interface { Quack() } type Animal struct { name string } func (animal Animal) Quack() { fmt.Println(animal.name, ": Quack! Quack! Like a duck!") } func main() { unknownAnimal := Animal{name: "Unknown"} var equivalent Duck equivalent = unknownAnimal equivalent.Quack() }
運(yùn)行上面的代碼輸出:
Unknown : Quack! Quack! Like a duck!
下面用 Java 語(yǔ)言來(lái)實(shí)現(xiàn):
interface Duck { void Quack(); } class SomeAnimal implements Duck { String name; public SomeAnimal(String name) { this.name = name; } public void Quack() { System.out.println(name + ": Quack! Quack! I am a duck!"); } } public class Test { public static void main(String []args){ SomeAnimal unknownAnimal = new SomeAnimal("Unknown"); Duck equivalent = unknownAnimal; equivalent.Quack(); } }
兩相比較就能看出:Go 將對(duì)象與對(duì)其的操作(方法或函數(shù))解耦得更徹底。Go 并不需要一個(gè)對(duì)象通過(guò)類型系統(tǒng)來(lái)保證實(shí)現(xiàn)了某個(gè)接口(is a),而只需要這個(gè)對(duì)象實(shí)現(xiàn)了某個(gè)接口的方法即可(like a),而且類型聲明與方法聲明或?qū)崿F(xiàn)也是松耦合的形式。如果稍微轉(zhuǎn)換一下方法的實(shí)現(xiàn)方式:
func (animal Animal) Quack() { fmt.Println(animal.name, ": Quack! Quack! Like a duck!") }
為:
func Quack(animal Animal) { fmt.Println(animal.name, ": Quack! Quack! Like a duck!") }
是不是就和普通方法并無(wú)二致了?
在深入淺出 Cocoa 之消息一文中我曾分析過(guò) Objective C 的消息調(diào)用過(guò)程:
Bird * aBird = [[Bird alloc] init]; [aBird fly];
中對(duì) fly 的調(diào)用,編譯器通過(guò)插入一些代碼,將之轉(zhuǎn)換為對(duì)方法具體實(shí)現(xiàn) IMP 的調(diào)用,這個(gè) IMP 是通過(guò)在 Bird 的類結(jié)構(gòu)中的方法鏈表中查找名稱為 fly 的選擇子 SEL 對(duì)應(yīng)的具體方法實(shí)現(xiàn)找到的,編譯器會(huì)將消息調(diào)用轉(zhuǎn)換為對(duì)消息函數(shù) objc_msgSend的調(diào)用:
objc_msgSend(aBird, @selector(fly));
無(wú)論是 Objective C 的消息機(jī)制還是 Qt 中的 Signal/Slot 機(jī)制,可以說(shuō)都是在嘗試將對(duì)象本身(數(shù)據(jù))與對(duì)對(duì)象的操作(消息)解耦,但 Go 將這個(gè)工作在語(yǔ)言層面做得更加徹底,這樣不僅避免多重繼承問(wèn)題,還體現(xiàn)出面向?qū)ο笤O(shè)計(jì)中最要緊的事情:對(duì)象間的消息傳遞。
實(shí)現(xiàn)
interface 實(shí)際上就是一個(gè)結(jié)構(gòu)體,包含兩個(gè)成員。其中一個(gè)成員是指向具體數(shù)據(jù)的指針,另一個(gè)成員中包含了類型信息??战涌诤蛶Х椒ǖ慕涌诼杂胁煌?,下面分別是空接口和帶方法的接口是使用的數(shù)據(jù)結(jié)構(gòu):
struct Eface { Type* type; void* data; }; struct Iface { Itab* tab; void* data; }; struct Itab { InterfaceType* inter; Type* type; Itab* link; int32 bad; int32 unused; void (*fun[])(void); }; struct Type { uintptr size; uint32 hash; uint8 _unused; uint8 align; uint8 fieldAlign; uint8 kind; Alg *alg; void *gc; String *string; UncommonType *x; Type *ptrto; };
先看Eface,它是interface{}底層使用的數(shù)據(jù)結(jié)構(gòu)。數(shù)據(jù)域中包含了一個(gè)void*指針,和一個(gè)類型結(jié)構(gòu)體的指針。interface{}扮演的角色跟C語(yǔ)言中的void*是差不多的,Go中的任何對(duì)象都可以表示為interface{}。不同之處在于,interface{}中有類型信息,于是可以實(shí)現(xiàn)反射。
不同類型數(shù)據(jù)的類型信息結(jié)構(gòu)體并不完全一致,Type是類型信息結(jié)構(gòu)體中公共的部分,其中size描述類型的大小,UncommonType是指向一個(gè)函數(shù)指針的數(shù)組,收集了這個(gè)類型的具體實(shí)現(xiàn)的所有方法。
在reflect包中有個(gè)KindOf函數(shù),返回一個(gè)interface{}的Type,其實(shí)該函數(shù)就是簡(jiǎn)單的取Eface中的Type域。
Iface和Eface略有不同,它是帶方法的interface底層使用的數(shù)據(jù)結(jié)構(gòu)。data域同樣是指向原始數(shù)據(jù)的,Itab中不僅存儲(chǔ)了Type信息,而且還多了一個(gè)方法表fun[]。一個(gè)Iface中的具體類型中實(shí)現(xiàn)的方法會(huì)被拷貝到Itab的fun數(shù)組中。
Type的UncommonType中有一個(gè)方法表,某個(gè)具體類型實(shí)現(xiàn)的所有方法都會(huì)被收集到這張表中。reflect包中的Method和MethodByName方法都是通過(guò)查詢這張表實(shí)現(xiàn)的。表中的每一項(xiàng)是一個(gè)Method,其數(shù)據(jù)結(jié)構(gòu)如下:
struct Method { String *name; String *pkgPath; Type *mtyp; Type *typ; void (*ifn)(void); void (*tfn)(void); };
Iface的Itab的InterfaceType中也有一張方法表,這張方法表中是接口所聲明的方法。其中每一項(xiàng)是一個(gè)IMethod,數(shù)據(jù)結(jié)構(gòu)如下:
struct IMethod { String *name; String *pkgPath; Type *type; };
跟上面的Method結(jié)構(gòu)體對(duì)比可以發(fā)現(xiàn),這里是只有聲明沒(méi)有實(shí)現(xiàn)的。
Iface中的Itab的func域也是一張方法表,這張表中的每一項(xiàng)就是一個(gè)函數(shù)指針,也就是只有實(shí)現(xiàn)沒(méi)有聲明。
類型轉(zhuǎn)換時(shí)的檢測(cè)就是看Type中的方法表是否包含了InterfaceType的方法表中的所有方法,并把Type方法表中的實(shí)現(xiàn)部分拷到Itab的func那張表中。
注意事項(xiàng)
一個(gè)interface在沒(méi)有進(jìn)行初始化時(shí),對(duì)應(yīng)的值是nil。也就是說(shuō):
var v interface{}
此時(shí)v就是一個(gè)nil。在底層存儲(chǔ)上,它是一個(gè)空指針。
與之不同的情況
var obj *T var v interface{} v = obj
此時(shí)v是一個(gè)interface,它的值是nil,也就是說(shuō)其data域?yàn)榭?,但它自身不為nil。
下面來(lái)看個(gè)例子就明白了:
Go語(yǔ)言中的error類型實(shí)際上是抽象了Error()方法的error接口:
type error interface { Error() string }
有如下代碼:
type Error struct { errCode uint8 } func (e *Error) Error() string { switch e.errCode { default: return "unknown error" } } func test_checkError() { var e *Error if e == nil { fmt.Println("e is nil") } else { fmt.Println("e is not nil") } var err error err = e if err == nil { fmt.Println("err is nil") } else { fmt.Println("err is not nil") } }
運(yùn)行test_checkError()輸出:
e is nil
err is not nil
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注創(chuàng)新互聯(lián)成都網(wǎng)站設(shè)計(jì)公司行業(yè)資訊頻道,感謝您對(duì)創(chuàng)新互聯(lián)成都網(wǎng)站設(shè)計(jì)公司的支持。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、網(wǎng)站設(shè)計(jì)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。
分享題目:如何在golang中使用interface-創(chuàng)新互聯(lián)
網(wǎng)頁(yè)地址:http://jinyejixie.com/article42/egdhc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站、微信公眾號(hào)、全網(wǎng)營(yíng)銷推廣、外貿(mào)網(wǎng)站建設(shè)、網(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í)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容