新聞中心
如果一個任意類型 T 的方法集為一個接口類型的方法集的超集,則我們說類型 T 實現(xiàn)了此接口類型。T 可以是一個非接口類型,也可以是一個接口類型。

為豐順等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及豐順網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都網(wǎng)站建設(shè)、網(wǎng)站制作、豐順網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!
實現(xiàn)關(guān)系在Go語言中是隱式的。兩個類型之間的實現(xiàn)關(guān)系不需要在代碼中顯式地表示出來。Go語言中沒有類似于 implements 的關(guān)鍵字。 Go編譯器將自動在需要的時候檢查兩個類型之間的實現(xiàn)關(guān)系。
接口定義后,需要實現(xiàn)接口,調(diào)用方才能正確編譯通過并使用接口。接口的實現(xiàn)需要遵循兩條規(guī)則才能讓接口可用。
接口被實現(xiàn)的條件一:接口的方法與實現(xiàn)接口的類型方法格式一致
在類型中添加與接口簽名一致的方法就可以實現(xiàn)該方法。簽名包括方法中的名稱、參數(shù)列表、返回參數(shù)列表。也就是說,只要實現(xiàn)接口類型中的方法的名稱、參數(shù)列表、返回參數(shù)列表中的任意一項與接口要實現(xiàn)的方法不一致,那么接口的這個方法就不會被實現(xiàn)。
為了抽象數(shù)據(jù)寫入的過程,定義 DataWriter 接口來描述數(shù)據(jù)寫入需要實現(xiàn)的方法,接口中的 WriteData() 方法表示將數(shù)據(jù)寫入,寫入方無須關(guān)心寫入到哪里。實現(xiàn)接口的類型實現(xiàn) WriteData 方法時,會具體編寫將數(shù)據(jù)寫入到什么結(jié)構(gòu)中。這里使用file結(jié)構(gòu)體實現(xiàn) DataWriter 接口的 WriteData 方法,方法內(nèi)部只是打印一個日志,表示有數(shù)據(jù)寫入,詳細(xì)實現(xiàn)過程請參考下面的代碼。
數(shù)據(jù)寫入器的抽象:
package main
import (
"fmt"
)
// 定義一個數(shù)據(jù)寫入器
type DataWriter interface {
WriteData(data interface{}) error
}
// 定義文件結(jié)構(gòu),用于實現(xiàn)DataWriter
type file struct {
}
// 實現(xiàn)DataWriter接口的WriteData方法
func (d *file) WriteData(data interface{}) error {
// 模擬寫入數(shù)據(jù)
fmt.Println("WriteData:", data)
return nil
}
func main() {
// 實例化file
f := new(file)
// 聲明一個DataWriter的接口
var writer DataWriter
// 將接口賦值f,也就是*file類型
writer = f
// 使用DataWriter接口進(jìn)行數(shù)據(jù)寫入
writer.WriteData("data")
}代碼說明如下:
- 第 8 行,定義 DataWriter 接口。這個接口只有一個方法,即 WriteData(),輸入一個 interface{} 類型的 data,返回一個 error 結(jié)構(gòu)表示可能發(fā)生的錯誤。
- 第 17 行,file 的 WriteData() 方法使用指針接收器。輸入一個 interface{} 類型的 data,返回 error。
- 第 27 行,實例化 file 賦值給 f,f 的類型為 *file。
- 第 30 行,聲明 DataWriter 類型的 writer 接口變量。
- 第 33 行,將 *file 類型的 f 賦值給 DataWriter 接口的 writer,雖然兩個變量類型不一致。但是 writer 是一個接口,且 f 已經(jīng)完全實現(xiàn)了 DataWriter() 的所有方法,因此賦值是成功的。
- 第 36 行,DataWriter 接口類型的 writer 使用 WriteData() 方法寫入一個字符串。
運行代碼,輸出如下:
WriteData: data
本例中調(diào)用及實現(xiàn)關(guān)系如下圖所示。
圖:WriteWriter的實現(xiàn)過程
當(dāng)類型無法實現(xiàn)接口時,編譯器會報錯,下面列出常見的幾種接口無法實現(xiàn)的錯誤。
1) 函數(shù)名不一致導(dǎo)致的報錯
在以上代碼的基礎(chǔ)上嘗試修改部分代碼,造成編譯錯誤,通過編譯器的報錯理解如何實現(xiàn)接口的方法。首先,修改 file 結(jié)構(gòu)的 WriteData() 方法名,將這個方法簽名(第17行)修改為:
func (d *file) WriteDataX(data interface{}) error {編譯代碼,報錯:
cannot use f (type *file) as type DataWriter in assignment:
*file does not implement DataWriter (missing WriteData method)
報錯的位置在第 33 行。報錯含義是:不能將 f 變量(類型*file)視為 DataWriter 進(jìn)行賦值。原因:*file 類型未實現(xiàn) DataWriter 接口(丟失 WriteData 方法)。
WriteDataX 方法的簽名本身是合法的。但編譯器掃描到第 33 行代碼時,發(fā)現(xiàn)嘗試將 *file 類型賦值給 DataWriter 時,需要檢查 *file 類型是否完全實現(xiàn)了 DataWriter 接口。顯然,編譯器因為沒有找到 DataWriter 需要的 WriteData() 方法而報錯。
2) 實現(xiàn)接口的方法簽名不一致導(dǎo)致的報錯
將修改的代碼恢復(fù)后,再嘗試修改 WriteData() 方法,把 data 參數(shù)的類型從 interface{} 修改為 int 類型,代碼如下:
func (d *file) WriteData(data int) error {編譯代碼,報錯:
cannot use f (type *file) as type DataWriter in assignment:
*file does not implement DataWriter (wrong type for WriteData method)
have WriteData(int) error
want WriteData(interface {}) error
這次未實現(xiàn) DataWriter 的理由變?yōu)椋ㄥe誤的 WriteData() 方法類型)發(fā)現(xiàn) WriteData(int)error,期望 WriteData(interface{})error。
這種方式的報錯就是由實現(xiàn)者的方法簽名與接口的方法簽名不一致導(dǎo)致的。
接口被實現(xiàn)的條件二:接口中所有方法均被實現(xiàn)
當(dāng)一個接口中有多個方法時,只有這些方法都被實現(xiàn)了,接口才能被正確編譯并使用。
在本節(jié)開頭的代碼中,為 DataWriter中 添加一個方法,代碼如下:
// 定義一個數(shù)據(jù)寫入器
type DataWriter interface {
WriteData(data interface{}) error
// 能否寫入
CanWrite() bool
}新增 CanWrite() 方法,返回 bool。此時再次編譯代碼,報錯:
cannot use f (type *file) as type DataWriter in assignment:
*file does not implement DataWriter (missing CanWrite method)
需要在 file 中實現(xiàn) CanWrite() 方法才能正常使用 DataWriter()。
Go語言的接口實現(xiàn)是隱式的,無須讓實現(xiàn)接口的類型寫出實現(xiàn)了哪些接口。這個設(shè)計被稱為非侵入式設(shè)計。
實現(xiàn)者在編寫方法時,無法預(yù)測未來哪些方法會變?yōu)榻涌凇R坏┠硞€接口創(chuàng)建出來,要求舊的代碼來實現(xiàn)這個接口時,就需要修改舊的代碼的派生部分,這一般會造成雪崩式的重新編譯。
提示
傳統(tǒng)的派生式接口及類關(guān)系構(gòu)建的模式,讓類型間擁有強(qiáng)耦合的父子關(guān)系。這種關(guān)系一般會以“類派生圖”的方式進(jìn)行。經(jīng)常可以看到大型軟件極為復(fù)雜的派生樹。隨著系統(tǒng)的功能不斷增加,這棵“派生樹”會變得越來越復(fù)雜。
對于Go語言來說,非侵入式設(shè)計讓實現(xiàn)者的所有類型均是平行的、組合的。如何組合則留到使用者編譯時再確認(rèn)。因此,使用GO語言時,不需要同時也不可能有“類派生圖”,開發(fā)者唯一需要關(guān)注的就是“我需要什么?”,以及“我能實現(xiàn)什么?”。
分享文章:創(chuàng)新互聯(lián)GO教程:Go語言實現(xiàn)接口的條件
標(biāo)題路徑:http://www.dlmjj.cn/article/cocsijd.html


咨詢
建站咨詢
