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

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


咨詢
建站咨詢
