Go開(kāi)發(fā)工程師
未來(lái)3-5年企業(yè)高性能項(xiàng)目不可替代的語(yǔ)言,從基礎(chǔ)到項(xiàng)目實(shí)戰(zhàn)再到重構(gòu),真正從入門(mén)到精通
在Go語(yǔ)言中,一個(gè)接口類(lèi)型總是代表著某一種類(lèi)型(即所有實(shí)現(xiàn)它的類(lèi)型)的行為。一個(gè)接口類(lèi)型的聲明通常會(huì)包含關(guān)鍵字type
、類(lèi)型名稱(chēng)、關(guān)鍵字interface
以及由花括號(hào)包裹的若干方法聲明。示例如下:
type Animal interface { Grow() Move(string) string }
注意,接口類(lèi)型中的方法聲明是普通的方法聲明的簡(jiǎn)化形式。它們只包括方法名稱(chēng)、參數(shù)聲明列表和結(jié)果聲明列表。其中的參數(shù)的名稱(chēng)和結(jié)果的名稱(chēng)都可以被省略。不過(guò),出于文檔化的目的,我還是建議大家在這里寫(xiě)上它們。因此,Move
方法的聲明至少應(yīng)該是這樣的:
Move(new string) (old string)
如果一個(gè)數(shù)據(jù)類(lèi)型所擁有的方法集合中包含了某一個(gè)接口類(lèi)型中的所有方法聲明的實(shí)現(xiàn),那么就可以說(shuō)這個(gè)數(shù)據(jù)類(lèi)型實(shí)現(xiàn)了那個(gè)接口類(lèi)型。所謂實(shí)現(xiàn)一個(gè)接口中的方法是指,具有與該方法相同的聲明并且添加了實(shí)現(xiàn)部分(由花括號(hào)包裹的若干條語(yǔ)句)。相同的方法聲明意味著完全一致的名稱(chēng)、參數(shù)類(lèi)型列表和結(jié)果類(lèi)型列表。其中,參數(shù)類(lèi)型列表即為參數(shù)聲明列表中除去參數(shù)名稱(chēng)的部分。一致的參數(shù)類(lèi)型列表意味著其長(zhǎng)度以及順序的完全相同。對(duì)于結(jié)果類(lèi)型列表也是如此。
例如,如果你正確地完成了上一小節(jié)的練習(xí)的話(huà),*Person
類(lèi)型(注意,不是Person
類(lèi)型)就會(huì)擁有一個(gè)Move
方法。該方法會(huì)是Animal
接口的Move
方法的一個(gè)實(shí)現(xiàn)。再加上我們?cè)谥盀樗帉?xiě)的那個(gè)Grow
方法,*Person
類(lèi)型就可以被看做是Animal
接口的一個(gè)實(shí)現(xiàn)類(lèi)型了。
你可能已經(jīng)意識(shí)到,我們無(wú)需在一個(gè)數(shù)據(jù)類(lèi)型中聲明它實(shí)現(xiàn)了哪個(gè)接口。只要滿(mǎn)足了“方法集合為其超集”的條件,就建立了“實(shí)現(xiàn)”關(guān)系。這是典型的無(wú)侵入式的接口實(shí)現(xiàn)方法。
好了,現(xiàn)在我們已經(jīng)認(rèn)為*Person
類(lèi)型實(shí)現(xiàn)了Animal
接口。但是Go語(yǔ)言編譯器是否也這樣認(rèn)為呢?這顯然需要一種顯式的判定方法。在Go語(yǔ)言中,這種判定可以用類(lèi)型斷言來(lái)實(shí)現(xiàn)。不過(guò),在這里,我們是不能在一個(gè)非接口類(lèi)型的值上應(yīng)用類(lèi)型斷言來(lái)判定它是否屬于某一個(gè)接口類(lèi)型的。我們必須先把前者轉(zhuǎn)換成空接口類(lèi)型的值。這又涉及到了Go語(yǔ)言的類(lèi)型轉(zhuǎn)換。
Go語(yǔ)言的類(lèi)型轉(zhuǎn)換規(guī)則定義了是否能夠以及怎樣可以把一個(gè)類(lèi)型的值轉(zhuǎn)換另一個(gè)類(lèi)型的值。另一方面,所謂空接口類(lèi)型即是不包含任何方法聲明的接口類(lèi)型,用interface{}
表示,常簡(jiǎn)稱(chēng)為空接口。正因?yàn)榭战涌诘亩x,Go語(yǔ)言中的包含預(yù)定義的任何數(shù)據(jù)類(lèi)型都可以被看做是空接口的實(shí)現(xiàn)。我們可以直接使用類(lèi)型轉(zhuǎn)換表達(dá)式把一個(gè)*Person
類(lèi)型轉(zhuǎn)換成空接口類(lèi)型的值,就像這樣:
p := Person{"Robert", "Male", 33, "Beijing"} v := interface{}(&p)
請(qǐng)注意第二行。在類(lèi)型字面量后跟由圓括號(hào)包裹的值(或能夠代表它的變量、常量或表達(dá)式)就構(gòu)成了一個(gè)類(lèi)型轉(zhuǎn)換表達(dá)式,意為將后者轉(zhuǎn)換為前者類(lèi)型的值。在這里,我們把表達(dá)式&p
的求值結(jié)果轉(zhuǎn)換成了一個(gè)空接口類(lèi)型的值,并由變量v
代表。注意,表達(dá)式&p
(&
是取址操作符)的求值結(jié)果是一個(gè)*Person
類(lèi)型的值,即p
的指針。
在這之后,我們就可以在v
上應(yīng)用類(lèi)型斷言了,即:
h, ok := v.(Animal)
類(lèi)型斷言表達(dá)式v.(Animal)
的求值結(jié)果可以有兩個(gè)。第一個(gè)結(jié)果是被轉(zhuǎn)換后的那個(gè)目標(biāo)類(lèi)型(這里是Animal
)的值,而第二個(gè)結(jié)果則是轉(zhuǎn)換操作成功與否的標(biāo)志。顯然,ok
代表了一個(gè)bool
類(lèi)型的值。它也是這里判定實(shí)現(xiàn)關(guān)系的重要依據(jù)。
至此,我們掌握了接口類(lèi)型、實(shí)現(xiàn)類(lèi)型以及實(shí)現(xiàn)關(guān)系判定的重要知識(shí)和技巧。關(guān)于Go語(yǔ)言的類(lèi)型轉(zhuǎn)換規(guī)則的更多細(xì)節(jié)請(qǐng)參看Go語(yǔ)言規(guī)范或《Go并發(fā)編程實(shí)戰(zhàn)》中的相關(guān)內(nèi)容。而至于為什么只有*Person
類(lèi)型才實(shí)現(xiàn)了Animal
接口,請(qǐng)參看后面兩節(jié)。
在源碼文件的第10行處加入若干代碼,使該文件不出現(xiàn)任何編譯錯(cuò)誤,并且運(yùn)行該文件會(huì)使標(biāo)準(zhǔn)輸出上出現(xiàn)true, &{Little C 2 In the house}
。
在第10行加入的代碼可以是:
type Cat struct { Name string Age uint8 Location string } func (cat *Cat) Grow() { cat.Age++ } func (cat *Cat) Move(new string) string { old := cat.Location cat.Location = new return old }
注意,答案不是唯一的。
請(qǐng)驗(yàn)證,完成請(qǐng)求
由于請(qǐng)求次數(shù)過(guò)多,請(qǐng)先驗(yàn)證,完成再次請(qǐng)求
打開(kāi)微信掃碼自動(dòng)綁定
綁定后可得到
使用 Ctrl+D 可將課程添加到書(shū)簽
舉報(bào)