這是它的優(yōu)點(diǎn),因?yàn)榫幾g器在編譯時(shí)不去確定你傳的到底是什么類型,你傳一個(gè)string,它能接收,你傳一個(gè)對(duì)象struct,它也能接收,它只有一個(gè)要求,實(shí)現(xiàn)我要求實(shí)現(xiàn)的方法!
創(chuàng)新互聯(lián)公司主要從事成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站、成都外貿(mào)網(wǎng)站建設(shè)公司、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)六安,10多年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18982081108
既然interface是不限定類型,是通用類型,這是一種開放表現(xiàn),這種開放怎么實(shí)現(xiàn)的呢?方差敬法就是不去檢驗(yàn)?zāi)愕念愋?,既然不檢驗(yàn)?zāi)且膊蝗ビ涗浤愕念愋停。。?!注意interface不記錄你的類型,所以不管你是string,struct,int,我都不管,我都不記錄,我只記錄你的地址,結(jié)果是編譯器在編譯時(shí)也不知道你是什么類型,你有什么字段!
但是現(xiàn)在有一個(gè)問題,編譯器也沒辦法確定一個(gè)interface以前是什么類型?。ň幾g時(shí))這就是因果關(guān)系:為了達(dá)到通用,interface不做確定工作,結(jié)果就是interface也不知道以前的類型。
一個(gè)類型轉(zhuǎn)接口的過程,就是放棄自我類型的過程,變成了沒有類型。
這樣做有什么好處呢,很顯然是:通用,如果把一個(gè)函數(shù)的傳入?yún)?shù)設(shè)置為空接口(interface{}),那么任何類型當(dāng)做參數(shù)都能夠調(diào)用該接口,最好的例子就是:
它就是一個(gè)很標(biāo)準(zhǔn)的例子,println傳入?yún)?shù)可以是任何類型,都能打印出它的值。
當(dāng)然你可以說你記得,因?yàn)槭悄惆阉D(zhuǎn)換成interface,你理所當(dāng)然的記得,可編譯器不知道啊,interface不包含類型,也就是說你沒有讓它去記錄,所以它不知道。
針對(duì)這個(gè)問題,go語言給了一個(gè)解決方案,斷言,當(dāng)將一個(gè)interface轉(zhuǎn)換成它原來類型的時(shí)候,在它后面指明它的原來類型,這樣編譯器就知道該按照什么類型去解析了。(其實(shí)說白了,這就是通過人的記憶,編譯器不知道是什么類型,你告訴編譯器就可以了)
斷言其實(shí)是先獲取interface的動(dòng)態(tài)類型,然后與你指定的類型做判斷,如果一致,將它轉(zhuǎn)換成你指定的類型。如果不知道動(dòng)態(tài)類型,可以看這篇文章:
從報(bào)錯(cuò)可以看出, 不能直接轉(zhuǎn)換,需要對(duì)接口先進(jìn)行斷言
通常情況下,一個(gè)變量在確定類型的情況下編譯器知道他有哪些功能(注意,這里是針對(duì)編譯時(shí)),比如一個(gè)int類型,編譯器在編譯時(shí)知道能對(duì)他加減int,不能加減float,如果你這么做我就給你報(bào)錯(cuò)。一個(gè)struct包含哪些字段,不包含哪些字段,我定義一個(gè)user結(jié)構(gòu)體,里面只有name和age兩個(gè)字段,那么你只能取我這兩字段的值,你如果取height,我就給你報(bào)錯(cuò)。
這些都是正常情況下的,但是對(duì)于一個(gè)接口呢,編譯器會(huì)變成瞎子!在編譯的時(shí)候它不知道你原來是什么類型,所以它也沒法確定你包含什么字段,同樣是之前那個(gè)user結(jié)構(gòu)體,當(dāng)把它轉(zhuǎn)換成接口以后,編譯器就對(duì)它的類型一無所知了,你獲取name字段,這有接口有沒有呢?編譯器不知道!你請(qǐng)求height字段,這個(gè)泛型有沒有呢?編譯器仍然不知道。所以你編譯時(shí)不能修改接口里的數(shù)據(jù),既然編譯時(shí) 不能修改,那就只能在運(yùn)行時(shí)修改了。
這個(gè)時(shí)候就該反射登場了,它能夠在運(yùn)行時(shí)修改接口的數(shù)據(jù),通過追根溯源,獲取接口底層的實(shí)際數(shù)據(jù)和類型,讓你能夠?qū)涌诘脑磾?shù)據(jù)進(jìn)行操作。
換一種大白話的說法,反射就是刨根凳慶友問底,獲取這個(gè)接口究竟是怎么產(chǎn)生的,因?yàn)槟呐乱粋€(gè)類型轉(zhuǎn)變成接口時(shí)放棄了自己的棗槐類型,但是它的本質(zhì)不會(huì)變的,就像趙本山的小品里所說:小樣,別以為你脫掉馬甲我就不認(rèn)識(shí)你了!對(duì),它的底層里仍然存儲(chǔ)了它的數(shù)據(jù)類型,只是藏的比較深,一般手段拿不到,但我們?nèi)匀荒軌蛲ㄟ^反射(這個(gè)包根問底的工具)來確定你究竟包含哪些字段和值,確定你究竟是蛇還是脫了馬甲的烏龜!
所謂Go語言式的接口,就是不用顯示聲明類型T實(shí)現(xiàn)了接口I,只要類型T的公開方法完全滿足接口I的要求,就可以把類型T的對(duì)象用在需要接口I的地方。這種做法的學(xué)名叫做Structural Typing,有人也把它看作是一種靜態(tài)的Duck Typing。除了Go的接口以外,類似的東西也有比如Scala里的Traits等等。有人覺得這個(gè)特性很好,但我個(gè)人并不喜歡這種做法,所以在這里談?wù)勊娜秉c(diǎn)。當(dāng)然這跟動(dòng)態(tài)語言靜態(tài)語言的討論類似,不能簡單粗暴的下一個(gè)“好”或“不好”察轎的結(jié)論。
我的觀點(diǎn):
Go的隱式接口Duck Typing確實(shí)不是新技術(shù), 但是在主流靜態(tài)編程語言中支持Duck Typing應(yīng)該是很少的(不清楚目前是否只有Go語言支持).
靜態(tài)類型和動(dòng)態(tài)類型雖然沒有絕對(duì)的好和不好, 但是每個(gè)都是有自己的優(yōu)勢的, 沒有哪一個(gè)可以包辦一切. 而Go是試圖結(jié)合靜態(tài)類型和動(dòng)態(tài)類型(interface)各自睜沒虛的優(yōu)勢.
那么就從頭談起:什么是接口。其實(shí)通俗的講,接口就是一個(gè)協(xié)議,規(guī)定悉燃了一組成員,例如.NET里的ICollection接口:
public interface ICollection {
int Count { get; }
object SyncRoot { get; }
bool IsSynchronized { get; }
void CopyTo(Array array, int index);
}
這就是一個(gè)協(xié)議的全部了嗎?事實(shí)并非如此,其實(shí)接口還規(guī)定了每個(gè)行為的“特征”。打個(gè)比方,這個(gè)接口的Count除了需要返回集合內(nèi)元素的數(shù)目以外,還隱含了它需要在O(1)時(shí)間內(nèi)返回這個(gè)要求。這樣一個(gè)使用了ICollection接口的方法才能放心地使用Count屬性來獲取集合大小,才能在知道這些特征的情況下選用正確的算法來編寫程序,而不用擔(dān)心帶來性能問題,這才能實(shí)現(xiàn)所謂的“面向接口編程”。當(dāng)然這種“特征”并不但指“性能”上的,例如Count還包含了例如“不修改集合內(nèi)容”這種看似十分自然的隱藏要求,這都是ICollection協(xié)議的一部分。
在正常的測試中,當(dāng)我們需要進(jìn)閉橘行接口測試時(shí),通常使用接口調(diào)試工具,如postman進(jìn)行接口測試
目前我在嘗試使用Go語言進(jìn)行接口測試,使用的庫均為Go自帶的庫。
注:當(dāng)前采用的接碧瞎口為時(shí)事新聞接口,每天可以請(qǐng)求100次,需要的同轎慧團(tuán)學(xué),可以自行使用。