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