Golang中的Interface(接口)全面解析_第1頁
Golang中的Interface(接口)全面解析_第2頁
Golang中的Interface(接口)全面解析_第3頁
Golang中的Interface(接口)全面解析_第4頁
Golang中的Interface(接口)全面解析_第5頁
已閱讀5頁,還剩10頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

Golang中的Interface(接?),全?解析Go語?中的interface沒有強(qiáng)制要求實(shí)現(xiàn)?法,但是interface是go中?常強(qiáng)?的?具之?。任?類型都可以實(shí)現(xiàn)interface中的?法,interface中的值可以代表是各種類型的值,這就是Go中實(shí)現(xiàn)多態(tài)的基礎(chǔ)什么是接?interface就是字?意思——接?,C++中可以?虛基類表?;Java中就是erface則是Golang更接近?向?qū)ο缶幊谭妒降牧?個(gè)難點(diǎn)interface是?法簽名的?個(gè)集合,這些?法可以被任?類型通過?法實(shí)現(xiàn)。因此接?就是對(duì)象?為的申明(不是定義,僅僅表??法簽名,也可以稱作函數(shù)原型)。例叫,如果在?個(gè)接?中申明了Walk?法簽名代表?路,Bark?法簽名表?狗叫,然后我們有個(gè)結(jié)構(gòu)體對(duì)象Dog,我們就說Dog實(shí)現(xiàn)了這個(gè)接?。所以,接?的任務(wù)就是提供?法簽名,?法簽名由?法名,輸?參數(shù),返回值**三部分組成,任?類型可以實(shí)現(xiàn)這些?法,?如struct結(jié)構(gòu)體。如果你是?個(gè)OOP(?向?qū)ο螅╊愋偷某绦騿T,你可能?過implement關(guān)鍵字來實(shí)現(xiàn)?個(gè)接?,但是在Golang中,你不需要明確的使?關(guān)鍵字來表?你實(shí)現(xiàn)了?個(gè)接?,如果你使?的類型實(shí)現(xiàn)了?個(gè)接?中的所有?法簽名,那么Golang就默認(rèn)你實(shí)現(xiàn)了這個(gè)接??;蚨鄠€(gè)?法,?法的名字,參數(shù),返回值和接?中的?法簽名完全?致,并且接?中的所有?法簽名在這個(gè)類型中都存在,那么我們稱為實(shí)現(xiàn)了這個(gè)接?如果我們說?個(gè)東西,?起來像鴨?,游泳像鴨?,并且叫起來像鴨?,那么在Golang中我們就認(rèn)為它就是?只鴨??!申明?個(gè)接?類似struct的申明?法,我們需要使?interface關(guān)鍵字來定義類型別名來?便使?接?。typeShapeinterface{Area()float64//?積Perimeterfloat64//周長(zhǎng)}在上?的例?中,我們定義了?個(gè)Shape接?,其中包含了兩個(gè)?法簽名:Area,Perimeter,?形參,返回float64值。任何類型,如果實(shí)現(xiàn)了和這兩個(gè)簽名形式?樣*(同樣的?法名,同樣的傳參,同樣的返回值)*的?法,我們就稱這個(gè)類型實(shí)現(xiàn)了Shape這個(gè)接?由于接?是?種類似結(jié)構(gòu)體的類型,我們可以創(chuàng)建?個(gè)Shape類型的變量s。上?的例?雖然簡(jiǎn)單,但是包含了很多信息,讓我來理理接?的概念。接?包含兩個(gè)類型(聽上去有點(diǎn)奇奇怪怪)和?個(gè)值。類型呢,?種是靜態(tài)類型,另?種就是動(dòng)態(tài)類型。靜態(tài)類型就是指接?本?的類型,?如上圖中的Shape就是靜態(tài)類型。值只有動(dòng)態(tài)值(沒有靜態(tài)值)。?個(gè)接?類型的變量只能表?實(shí)現(xiàn)了這個(gè)接?的動(dòng)態(tài)類型的值。這個(gè)動(dòng)態(tài)類型的變量就是這個(gè)接?的動(dòng)態(tài)值。(ok,不知道有沒有被我繞暈,暈了沒事,這?做好筆記,繼續(xù)往下看,回頭再來理解這?的概念就明?了。).從上?的例?中,我們可以發(fā)現(xiàn),接?類型變量值和類型都是nil。這是因?yàn)?,我們這?聲明的是Shape變量,它還沒有指定動(dòng)態(tài)類型,更沒有指定任何動(dòng)態(tài)值。當(dāng)我們?fmt.Println函數(shù)的時(shí)候,它接受的就是接?類型的參數(shù),第?個(gè)Println的參數(shù)就是指向了這個(gè)接?的動(dòng)態(tài)值,第?個(gè)Println的參數(shù)指向的就是這個(gè)接?的動(dòng)態(tài)類型。接?的實(shí)現(xiàn)結(jié)構(gòu)體Rect(實(shí)現(xiàn)了以上兩個(gè)?法)在上?的程序中,我們定義了?個(gè)Shape接?和Rect結(jié)構(gòu)體。然后Rect實(shí)現(xiàn)了Area和Perimeter?法,這就實(shí)現(xiàn)了Shape接?的所有?法簽名,所以我們就說Rect實(shí)現(xiàn)了Shape接?(這是Golang默認(rèn)的,?動(dòng)實(shí)現(xiàn))。但是我們并沒有明確的顯式指明Rect實(shí)現(xiàn)了Shape接?,(如果是java語?則需要使?implement指明實(shí)現(xiàn)了某個(gè)接?,?如publicclassRectimplementShape)。當(dāng)?個(gè)類型實(shí)現(xiàn)了某個(gè)接?,這個(gè)類型的變量也可以?它所實(shí)現(xiàn)的接?類型表?(或者說?接?類型的變量去存放)。我們可以聲明?個(gè)Shape接?類型的便令s,然后?s去接Rect類型的對(duì)象。(上圖24,25?代碼)因?yàn)镽ect實(shí)現(xiàn)了Shape接?,所以第25?代碼是完全有效的。我們可以看到,接?變量s的動(dòng)態(tài)類型就是Rect,動(dòng)態(tài)值就是Rect結(jié)構(gòu)體對(duì)象{5,4}是固定的,是動(dòng)態(tài)的有時(shí)候接?的動(dòng)態(tài)類型也叫做具體類型,因?yàn)槲覀儷@取接?類型的時(shí)候,它返回的是隱藏的動(dòng)態(tài)值的類型,它的靜態(tài)類型?直是隱式狀態(tài)。我們可以?s調(diào)?Area?法,因?yàn)镾hape接?定義了Area?法并且s的具體類型Rect也實(shí)現(xiàn)了該?法。所以s調(diào)?的?法是動(dòng)態(tài)對(duì)象的?法。我們也可以?較變量s和r的值,因?yàn)榇藭r(shí)他們動(dòng)態(tài)的類型都是Rect類型,動(dòng)態(tài)值都是{5,4}。讓我們改變s的動(dòng)態(tài)類型和動(dòng)態(tài)值:

我們定義了?個(gè)新的結(jié)構(gòu)體Circle,它也實(shí)現(xiàn)了Shape接?,所以我們可以給變量s賦?個(gè)Circle類型的值。我想你現(xiàn)在應(yīng)該明?了為啥接?的值和類型都是動(dòng)態(tài)的。猜猜下?程序會(huì)發(fā)?什么?上?程序中,我們刪除了Perimeter?法,這個(gè)程序就編譯不過并且拋出?個(gè)錯(cuò)誤。program.go:22:cannotuseRectliteral(typeRect)astypeShapeinassignment:RectdoesnotimplementShape(missingPerimetermethod)從上?的錯(cuò)誤中我們可以很容易的理解實(shí)現(xiàn)接?的要求:我們需要實(shí)現(xiàn)接?中申明的所有?法簽名。這也解釋了我之前說的要實(shí)現(xiàn)接?中的所有?法,看到這?應(yīng)該有了清晰的理解??战?當(dāng)?個(gè)接?沒有申明任何?法簽名,它就是空接?,?**interface{}**表?。因?yàn)榭战?沒有?法簽名,所以所有的類型都是隱式實(shí)現(xiàn)了空接??,F(xiàn)在你知道標(biāo)準(zhǔn)庫fmt中的Println函數(shù)是如何接收不同類型的參數(shù)沒?就是使?了空接?,讓我們看看Println的函數(shù)簽名funcPrintln(a...interface{})(nint,errerror)如你所見,Println是?個(gè)接收接?類型的可變參數(shù)函數(shù)。下?來更深?的了解?下.我們創(chuàng)建?個(gè)explain函數(shù),有?個(gè)空接?類型的輸?參數(shù),?返回值。?它來解釋動(dòng)態(tài)類型和空接?。上?的程序中,我們創(chuàng)建了?個(gè)?定義字符串類型MyString和?個(gè)結(jié)構(gòu)體Rect。因?yàn)閑xplain函數(shù)接收的空接?類型的參數(shù),所以我們可以傳??個(gè)MyString,Rect,或者其他類型的變量。因?yàn)樗蓄愋蛯?shí)現(xiàn)了空接?interface{},所以這樣使?是合法的。??次完美體現(xiàn)了多態(tài)的特性。explain的形參i靜態(tài)類型是接?類型,但是它的動(dòng)態(tài)類型是我們傳?參數(shù)的類型。多接?上?的程序中,我們創(chuàng)建了?個(gè)有Area?法Shape接?和?個(gè)?Volume?法的Object接?。結(jié)構(gòu)體Cube同時(shí)實(shí)現(xiàn)了這兩個(gè)?法,所以也就同時(shí)實(shí)現(xiàn)了這兩個(gè)接?。所以我可以把Cube類型的值賦值給Shape和Object接?類型的變量。我們指定變量s和o的動(dòng)態(tài)值都是c,我們可以?s調(diào)?Area?法,?o調(diào)?Volume?法,因?yàn)閟申明了Area?法簽名,o申明了Volume?法簽名,所以這樣?是合法的。但是如果我們?s調(diào)?Volume?法,?o調(diào)?Area?法,會(huì)發(fā)?什么呢?fmt.Println("volumeofsofinterfacetypeShapeis",s.Volume())fmt.Println("areaofoofinterfacetypeObjectis",o.Area())然后呢,就出現(xiàn)了?下的錯(cuò)誤:program.go:31:s.Volumeundefined(typeShapehasnofieldormethodVolume)program.go:32:o.Areaundefined(typeObjecthasnofieldormethodArea)這個(gè)程序是編譯不過的,因?yàn)閟的靜態(tài)類型是Shape,o的靜態(tài)類型是Object。但是Shape沒有定義Volume?法,Object沒有定義Area?法,所以就會(huì)產(chǎn)?以上錯(cuò)誤。為了讓上?程序正常運(yùn)?,我們需要設(shè)法獲取這些接?的動(dòng)態(tài)值——Cube類型對(duì)象(實(shí)現(xiàn)了這些接?的類型)。這時(shí)候我們就要?到類型斷?,下?有請(qǐng)類型斷?。類型斷?我們創(chuàng)建?個(gè)變量i,i是接?類型,這時(shí)候我們需要把i轉(zhuǎn)換成它所代表的的靜態(tài)類型,我們就可以使?語法:i.(Type),Type代表的?標(biāo)類型,這個(gè)類型實(shí)現(xiàn)了i的靜態(tài)類型接?。Go會(huì)檢查i的動(dòng)態(tài)類型是不是Type類型,如果是,就返回對(duì)應(yīng)的靜態(tài)值(靜態(tài)對(duì)象)。上?的程序中,Shape類型的變量s的動(dòng)態(tài)值是Cube類型的。我們可以使?s.(Cube)語法來獲取這個(gè)s的動(dòng)態(tài)值,并且賦值給s。這樣我們就可以?c調(diào)?Area和Volume?法了,因?yàn)閏是Cube類型的,Cube同時(shí)實(shí)現(xiàn)了這兩個(gè)?法。注意,如果使?類型斷?語法:i.(Type),但是接?變量i得動(dòng)態(tài)值不是Type類型的,也就是說,Type沒有實(shí)現(xiàn)i的接?,那么Go編譯器會(huì)拋出?個(gè)編譯錯(cuò)誤impossibletypeassertion:Typedoesnotimplementi(missingAreamethod)但是,即使Type實(shí)現(xiàn)了i的接?,如果i沒有賦予Type類型的靜態(tài)值,就是說i=nil,這時(shí)候執(zhí)?這個(gè)類型斷?的話,Go就會(huì)在程序運(yùn)?過程中拋出?個(gè)運(yùn)?錯(cuò)誤panic:interfaceconversion:main.Shapeisnil,notmain.Cube但是呢,我們還是有?法能避免運(yùn)?錯(cuò)誤的,需要?另?種類型斷?語法:value,ok:=i.(Type)在上?的語法中,我們可以?bool類型的變量ok來檢查i是否指向動(dòng)態(tài)類型Type的值。如果不是,那么ok就是false,并且vlaue就等于nil。這樣通過ok來判斷,程序在運(yùn)?過程中也不會(huì)報(bào)錯(cuò)了。因?yàn)榻?變量s的動(dòng)態(tài)值是Cube類型的,?Cube?實(shí)現(xiàn)了Object接?,所以第?個(gè)類型斷?是成功的。value1的靜態(tài)類型就是Object,value1也是指向s的動(dòng)態(tài)值{3}(通過Printf的打印結(jié)果可以看出來)。但是,因?yàn)榻?變量s的動(dòng)態(tài)類型Cube沒有實(shí)現(xiàn)Skin類型,所以ok2的值是false,value2的值是nil(接?類型的零值)。如果我們使?簡(jiǎn)化的類型斷?語法“value2:=s.(Skin)”,那么在程序運(yùn)?的時(shí)候就會(huì)拋出以下的錯(cuò)誤:panic:interfaceconversion:main.Cubeisnotmain.Skin:missingmethodColor?型對(duì)象直接去獲取它指向的動(dòng)態(tài)值的屬性信息。簡(jiǎn)??之,獲取任何接?類型沒有定義的屬性或者?法,都會(huì)引起運(yùn)?時(shí)錯(cuò)誤。所以在必要的時(shí)候,記得使?類型斷?進(jìn)?轉(zhuǎn)換和判斷。類型斷?不僅僅只是?來判斷某個(gè)接?是否指向了某個(gè)具體值。我們也?來從?個(gè)接?類型到另?個(gè)接?類型的轉(zhuǎn)換(請(qǐng)看上?的例?:s.(Skin);或者看)。SwitchpackagemainimportfmttypeMyStringstringtypeRectstruct{WidthfloatHeightfloat}funcexplain(iinterface{}){fmt.Printf("valuegivetoexplainfunctionisoftype:%Twithvalue:%v",i,i)}funcmain(){myString:=MyString{"hello,world"}r:=Rect{5.5,4.5}explain(myString)explain(r)}現(xiàn)在,讓我們看看空接?對(duì)的作?,上?的例?是之間空接?那?節(jié)中?的例?,explain函數(shù)有?形參是空接?類型的,我們可以傳任何參數(shù)進(jìn)去。但是如果有?個(gè)string類型的參數(shù),我們把這個(gè)參數(shù)傳?explain函數(shù)中,并且把這個(gè)字符串的轉(zhuǎn)成所有字母?寫冰打印。這時(shí)候我們?cè)撛趺醋瞿?。我們可?string包的ToUpper這個(gè)函數(shù),但是這個(gè)函數(shù)只接受字符串類型的參數(shù),在explain中使?ToUpper函數(shù)之前,我們需要確認(rèn)傳?的接?變量的動(dòng)態(tài)類型是否是字符串類型。這時(shí)候我們就可以?到Switch關(guān)鍵字了。Switch語法很類似之前?的類型斷?的語法:i.(Type),i是?個(gè)接?,type是?個(gè)內(nèi)置關(guān)鍵字。這?i.(type)得到的是這個(gè)接?的動(dòng)態(tài)類型,?不是類型斷??節(jié)中得到的是動(dòng)態(tài)值。讓我們來看個(gè)例?:在上?的例?中,我們?Switch修改了explain函數(shù),當(dāng)我們使?explain函數(shù)的時(shí)候,i接收的參數(shù)既包含了傳?參數(shù)的動(dòng)態(tài)類型和動(dòng)態(tài)值。在Switch中使?i.(type),我們可以獲取i的動(dòng)態(tài)類型。然后在Switch中使?:case關(guān)鍵字+類型,這種?式來判斷是否符合i的動(dòng)態(tài)類型。在casestring塊中,我們使?strings.ToUpper函數(shù)來把字符串轉(zhuǎn)換成?寫模式。但是strings.ToUpper函數(shù)只接受字符串類型參數(shù),所以我們需要?類型斷?來獲取影藏在i中的動(dòng)態(tài)值。接?的嵌套在Go語?中,?個(gè)接?不能實(shí)現(xiàn)或者擴(kuò)展另?個(gè)接?,只能通過組合的?式,把多個(gè)接?組合成?個(gè)新的接?。下?重寫Shape—Cube程序來感受?下:上?的程序中,因?yàn)镃ube實(shí)現(xiàn)了Area和Volume?法,所以Cube同時(shí)實(shí)現(xiàn)了Shape和Object接?。?因?yàn)镸aterial接?是由Shape和Object組合?成,所以Cube也實(shí)現(xiàn)了Material接?。就像匿名嵌套結(jié)構(gòu)體,這是可?的,所有內(nèi)嵌接?中的?法簽名也都屬于?接?,?接?可以隨意訪問。指針接收者和值接收者本?直到這?,所有?法都是?的值接收者的?式。如果使?指針接收者,這些程序還是否可??讓我們來檢驗(yàn)?下:在上?的程序中,Area?法屬于*Rect類型,因此Area的接收者會(huì)去獲取是Rect類型的指針(即使使?Rect類型的值去調(diào)?,底層也會(huì)轉(zhuǎn)換成*Rect類型去調(diào)?)。但是,上訴程序?qū)?huì)編譯不通過,go編譯器會(huì)報(bào)編譯錯(cuò)誤。program.go:27:cannotuseRectliteral(typeRect)astypeShapeinassignment:RectdoesnotimplementShape(Areamethodhaspointerreceiver)這是什么?!Rect明明已經(jīng)實(shí)現(xiàn)了Shape接?的所有?法簽名,這是怎么回事呢,Rect表?不服!憑什么提?RectdoesnotimplementShape。在仔細(xì)品品上?的錯(cuò)誤,后?還有?句Areamethodhaspointerreceiver。所以Area的接收者是指針類型將會(huì)發(fā)?什么情況呢。?個(gè)結(jié)構(gòu)類型的?法(?如上?的Rect結(jié)構(gòu)體的Area?法),它的接收者?論是這個(gè)結(jié)構(gòu)體的指針類型,還是值類型,我們都可以?r.Area()來調(diào)?,這是不會(huì)報(bào)錯(cuò)的,完全合法!但是,在實(shí)現(xiàn)接?的情況下,可能會(huì)有?點(diǎn)點(diǎn)的不同。上?程序中,接?s的動(dòng)態(tài)類型是Rect,Rect類型沒有實(shí)現(xiàn)Area?法,?是*Rect類型實(shí)現(xiàn)了Area?法。定的接收者類型去調(diào)?該?法。但是,在接?的實(shí)現(xiàn)中,Rect實(shí)現(xiàn)的?法,不代表***Rect**就實(shí)現(xiàn)了該?法。就像上?的程序,*Rect實(shí)現(xiàn)了Area?法,但是Rect沒有實(shí)現(xiàn)Area?法,Golang底層不會(huì)默認(rèn)Rect也實(shí)現(xiàn)了Area?法。所以讓上?的程序

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論